I have a problem with bidirectional many-to-many mapping in hibernate by annotation.
The setup is Student : StudentCertification with N:N relationship. The @ManyToMany(mappedby = …) annotation is used on the inverse non-owning side (StudentCertification) with @ManyToMany and @JoinTable annotation on the owner side (Student).
The problem is, when the records are stored by saving non-owning side only, no mapping table (Student_StudentCertification) is filled up whereas table of owning and non-owning side is filled up (see Hibernate log 2). Therefore, there is no N:N relationship in database, only not related two tables Student and StudentCertification exists. Note, all three mentioned tables are created (see the hibernate log 1). When the owning side object (Student) is saved, there is no problem. All tables are filled up. It indicates that the parameter mappedby does not work well and do not point at the owner side property where the description of N:N relationship is defined by annotation. The code used jUnit test to save 10 non-owning objects STUDENTCERTIFICATION which each of them has add 10 different students (see the jUnit code):
Could you help me, why the mappedby parameter is not enough??? Or where else could the problem be? Thanks.
Owning side STUDENT:
@Entity
@Table(name = "STUDENT")
public class Student {
//== VARIABLE INSTANCE FIELDS ==============================================
@Id
@GeneratedValue
@Column(name = "STUDENT_ID_COLUMN")
private int student_id;
@Column(name = "NAME_COLUMN", nullable = false)
private String student_name;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "STUDENT_STUDENTCERTIFICATION",
joinColumns = {@JoinColumn
(name = "STU_ID", referencedColumnName = "STUDENT_ID_COLUMN")},
inverseJoinColumns = {@JoinColumn
(name = "CER_ID", referencedColumnName = "CERTIFICATION_ID_COLUMN")} )
private List<StudentCertification> _listOfCertifications
= new ArrayList<StudentCertification>();
//== INSTANCE GETTERS AND SETTERS ==========================================
// . . . the rest of all getter and setters
}
NON-Ownining side STUDENTCERTIFICATION:
@Entity
@Table(name = "STUDENTCERTIFICATION")
public class StudentCertification {
//== VARIABLE INSTANCE FIELDS ==============================================
@Id
@GeneratedValue
@Column(name = "CERTIFICATION_ID_COLUMN")
private int _certification_id;
@Column(name = "CERTIFICATION_NAME_COLUMN", nullable = false)
private String _certification_name;
@ManyToMany(cascade = CascadeType.All, mappedBy = "_listOfCertifications")
private List<Student> _listOfStudents;
//== INSTANCE GETTERS AND SETTERS ==========================================
/**
* @return the _certification_id
*/
public int get_certification_id() {
return _certification_id;
}
// . . . the rest of all getter and setters
}
jUnit test:
public class TestHibernateManyToMany {
//== VARIABLE INSTANCE FIELDS ==============================================
/** The list of student and certification */
private List<Student> listSuccStud = new ArrayList<Student>();
private List<StudentCertification> listSuccCert = new ArrayList<StudentCertification>();
/**
* Sets the testing fixture up.
*
* @throws Exception the exception
*/
@Before
public void setUp() throws Exception {
//code for creation of list of 10 students and list of 10 certifications
}
//== TESTING CLASSES AND METHODS ===========================================
/**
* Test many to many, the given certification is related to the 10 students and then is saved
*/
@Test
public void testManyToManyBidir() {
// assign all students for each certification
for (StudentCertification cer : listSuccCert) {
cer.set_listOfStudents(listSuccStud);
Main.safeTheObjectIntoDatabase(cer); //saving certification
}
}
Main code saving the non-owning side model:
public class Main {
//== TESTING CLASSES AND METHODS ===========================================
/**
* Test method to save the object into database.
*
* @param object the object
*/
public static void safeTheObjectIntoDatabase(Object object) {
{SessionFactory sessionFactory = HibernateUtil.getSessionFactory();//create factory
Session session = sessionFactory.openSession();
Transaction transaction = null;
try{
transaction = session.beginTransaction();
session.save(object);
transaction.commit();
}
catch (Exception e)
{
if(transaction != null)
{
transaction.rollback();
}
throw new RuntimeException("Pri volani SQL nastala chyba", e);
}
finally
{
session.close();
}
}//block session factory
}
Hibernate log 1: Table creation
Hibernate: alter table STUDENT_STUDENTCERTIFICATION drop foreign key FK_j6up3gxynxgvtfax9105f0vbs
Hibernate: alter table STUDENT_STUDENTCERTIFICATION drop foreign key FK_tfdgl5fmkt2t1dae8p3fwpal5
Hibernate: drop table if exists STUDENT
Hibernate: drop table if exists STUDENTCERTIFICATION
Hibernate: drop table if exists STUDENT_STUDENTCERTIFICATION
Hibernate: create table STUDENT (STUDENT_ID_COLUMN integer not null auto_increment, NAME_COLUMN varchar(255) not null, primary key (STUDENT_ID_COLUMN))
Hibernate: create table STUDENTCERTIFICATION (CERTIFICATION_ID_COLUMN integer not null auto_increment, CERTIFICATION_NAME_COLUMN varchar(255) not null, primary key (CERTIFICATION_ID_COLUMN))
Hibernate: create table STUDENT_STUDENTCERTIFICATION (STU_ID integer not null, CER_ID integer not null)
Hibernate: alter table STUDENT_STUDENTCERTIFICATION add constraint FK_j6up3gxynxgvtfax9105f0vbs foreign key (CER_ID) references STUDENTCERTIFICATION (CERTIFICATION_ID_COLUMN)
Hibernate: alter table STUDENT_STUDENTCERTIFICATION add constraint FK_tfdgl5fmkt2t1dae8p3fwpal5 foreign key (STU_ID) references STUDENT (STUDENT_ID_COLUMN)
Hibernate log 2: Table insertion and update, !!! no mapping table insert !!!
Hibernate: insert into STUDENTCERTIFICATION (CERTIFICATION_NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENT (NAME_COLUMN) values (?)
Hibernate: insert into STUDENTCERTIFICATION (CERTIFICATION_NAME_COLUMN) values (?)
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
Hibernate: insert into STUDENTCERTIFICATION (CERTIFICATION_NAME_COLUMN) values (?)
Hibernate: update STUDENT set NAME_COLUMN=? where STUDENT_ID_COLUMN=?
... the similar pattern of code, !!! no mapping table STUDENT_STUDENTCERTIFICATION insert !!!