多对多关系的使用:
Student.hbm.xml
<class name="model.Student" table="student"
select-before-update="true"><!--把类和数表关联起来-->
<id name="id" unsaved-value="null"><!--id的产生方式是uuid.hex-->
<generator class="uuid.hex" />
</id>
<property name="cardId" type="string" /><!--映射号-->
<property name="name" type="string" /><!--映射学生名-->
<property name="age" type="int" /><!--映射学生岁数-->
<set name="courses" table="student_course"
cascade="none">
<key column="stu_id" />
<many-to-many class="model.Course"
column="course_id" />
</set>
</class>
Course.hbm.xml
<class name="model.Course" table="course"
select-before-update="true"><!--把类和数表关联起来-->
<id name="id" unsaved-value="null" ><!--id的产生方式是uuid.hex-->
<generator class="uuid.hex" />
</id>
<property name="name" type="string" /><!--映射课程名-->
<set name="students" table="student_course"
cascade="save-update">
<key column="course_id" />
<many-to-many class="model.Student"
column="stu_id" />
</set>
</class>
多对多关系需要配置的属性比较多,需要记住一个原则:<key column=””>总是和本身类的主键id相对应,而<column=””>总是和关联类的主键id相对应。对于上面的Student.hbm.xml,他有个关联类course,<key column=””>对应本身类,而本身类是student,所以应该填写stu_id;<column=””>对应关联类,关联类是Course,所以应该填写course_id。通过取得student对象而取得course对象集合的过程:首先取得student对象的主键值id,查找student.hbm.xml,根据“stu_id”找出相对应的“course_id”值,然后再去查找course.hbm.xml,找出course中对应的列名,然后根据“course_id”值在course表中找出相对应的集合。
添加关联关系
测试类:看某个学生的选课情况,
Student student = (Student)session.get(Student.class, "5abfe4c705ca8ee00105ca8ee42b0001");
List list = new ArrayList(student.getCourses());
for(int i = 0;i<list.size();i++){
Course course2 = (Course)list.get(i);
System.out.println(course2.getName());
}
控制台输出:
l Hibernate: select student0_.id as id0_0_, student0_.cardId as cardId0_0_, student0_.name as name0_0_, student0_.age as age0_0_ from student student0_ where student0_.id=?
l Hibernate: select courses0_.stu_id as stu1_1_, courses0_.course_id as course2_1_, course1_.id as id2_0_, course1_.name as name2_0_ from student_course courses0_ left outer join course course1_ on courses0_.course_id=course1_.id where courses0_.stu_id=?
l computer
l history
l music
现在该学生还想添加ecnomic课程,对于程序员来说只是为该学生添加了一个到ecnomic 的惯量,具体地说就是在student_course表中新添了一条记录,而student和course表都不用变更。
测试类:
session = HibernateUtil.currentSession(); //开启连接
tx = session.beginTransaction(); //开启事务
stu=(Student) session.createQuery("from Student s where s.name ='tomclus'").uniqueResult();
course=(Course) session.createQuery("from Course c where c.name='ecnomic'").uniqueResult();
stu.getCourses().add(course);
course.getStudents().add(stu);
控制台输出:
l Hibernate: select student0_.id as id0_, student0_.cardId as cardId0_, student0_.name as name0_, student0_.age as age0_ from student student0_ where student0_.name='tomclus'
l Hibernate: select course0_.id as id2_, course0_.name as name2_ from course course0_ where course0_.name='ecnomic'
l Hibernate: select courses0_.stu_id as stu1_1_, courses0_.course_id as course2_1_, course1_.id as id2_0_, course1_.name as name2_0_ from student_course courses0_ left outer join course course1_ on courses0_.course_id=course1_.id where courses0_.stu_id=?
l Hibernate: select students0_.course_id as course2_1_, students0_.stu_id as stu1_1_, student1_.id as id0_0_, student1_.cardId as cardId0_0_, student1_.name as name0_0_, student1_.age as age0_0_ from student_course students0_ left outer join student student1_ on students0_.stu_id=student1_.id where students0_.course_id=?
l Hibernate: insert into student_course (stu_id, course_id) values (?, ?)
l Hibernate: insert into student_course (course_id, stu_id) values (?, ?)
l ERROR [main] (JDBCExceptionReporter.java:78) - Duplicate entry '5abfe4c705ca8ee00105ca8ee42b0001-
第一句:执行hql语句记载student对象
第二句:执行hql语句加载course对象
第三句:通过辅助表左外连接取得student关联的所有课程
第四句:通过辅助表左外连接取得course关联的所有课程
第五句:由stu.getCourses().add(course);语句引入的插入语句
第六句:由course.getStudents().add(stu);语句引入的插入语句
第七句:抛出异常,第二次插入内容和第一次相同
由此可见,在多对多关系中,如果双方都有控制权(也就是双方都没有设置inverse=“true”),则双方都要把关联关系反应到数据库,因此才会有第五和第六条语句,插入的内容相同,导致违反数据库主键约束。
解决方法:
(1)在course.getStudents().add(stu); 和stu.getCourses().add(course)中只选择一条执行
(2)在某一方设置inverse=”true”,然后再执行语句时使用主控方进行操作(也就是没有inverse=“true”的哪一方)