4.多对多关系映射:
典型实例:一个学生可以有多个老师,同样一个老师可以有多个学生,对此设计如下:
学生studnet表:
column |
id |
name |
teachers |
老师teacher表:
column |
id |
name |
studnets |
在利用学生查到他所有的老师,我们一般会设计中间表,来查找,中间表用来把学生和老师关联,通过此表进行学生和老师之间的交互查找。
中间表teacher_student:
column |
teacher_id |
studnet_id |
|
复合主键 |
在数据库操作中,作以下说明:如果通过老师查找学生,过程:先通过teacher表查找到id,再到teacher_student表中以teacher.id==teacher_student.teacher_id为查询条件来查找studnent_id , 查找到studnet_id后,再以teacher_student.stucent_id==student.id为查询条件来查找所有学生的信息。 同样通过学生查老师,也是类似的过程。
>>步骤一、创建实体类Student、Teacher
Student类内容如下:省略getXXX()、setXXX()方法。
package com.asm.hibernate.domain; import java.util.Set; public class Student { private int id; private String name; private Set<Teacher> teachers; }
Teacher类内容如下:省略getXXX()、setXXX()方法。
package com.asm.hibernate.domain; import java.util.Set; public class Teacher { private int id; private String name; private Set<Student> students; }
>>步骤二、为两个实体创建配置文件(省略了前面的xml文档声明内容):Student.hbm.xml内容如下:
<hibernate-mapping package="com.asm.hibernate.domain"> <class name="Student"> <id name="id"> <generator class="native"/> </id> <property name="name"></property> <set name="teachers" table="teacher_student"> <key column="student_id" /> <many-to-many class="Student" column="teacher_id"/> </set> </class> </hibernate-mapping>
说明:这里重点说明最后的<set>配置:(1)Student中Set类型的属性配置一个<set>元素,其实在前面的一对多中已经出现了<set>元素的配置,我们可以这样认为“凡是要为某个Set类型的属性进行映射配置,都可以用<set>元素来配置”。 <set>中的table属性为关联表的名称。 (2)它的子元素<key>中的column为关联表中以该映射文件所映射的表的主键为外键的字段名称. (3)<many-to-many> coumn属性为关联表中以欲关联类对应表的主键为外键的字段名称。
Teacher.hbm.xml内容如下:
<hibernate-mapping package="com.asm.hibernate.domain"> <class name="Teacher"> <id name="id"> <generator class="native"/> </id> <property name="name"></property> <set name="students" table="teacher_student"> <key column="teacher_id" /> <many-to-many class="Student" column="student_id"/> </set> </class> </hibernate-mapping>
由于和Student.hbm.xml是类似的,这里不作说明,这样也就建立起了双向的多对多关联。
要注意他们所依赖的中间表为teacher_student,所以这里的<set>元素中的table属性和teacher映射文件相同,而特别要注意<key>和<many-to-many>中column中属性值的设定。
>>步骤三、在主配置文件中关联实体配置文件:只需要增加如下内容:
<mapping resource="com/asm/hibernate/domain/Teacher.hbm.xml" />
<mapping resource="com/asm/hibernate/domain/Student.hbm.xml" />
>>步骤四、编写测试文件ManyToManyTest.java:省略导入的包。
package com.asm.hibernate.test; public class ManyToManyTest { public static void main(String[] args) { add(); } static void add() { Session s = null; Transaction tr = null; try { s = HibernateUtil.getSession(); tr = s.beginTransaction(); Teacher t1 = new Teacher(); t1.setName("t1Name"); Teacher t2 = new Teacher(); t2.setName("t2Name"); Student s1 = new Student(); s1.setName("s1Name"); Student s2 = new Student(); s2.setName("s2Name"); // 再增加如下内容进行测试: Set<Teacher> ts = new HashSet<Teacher>(); ts.add(t1); ts.add(t2); Set<Student> ss = new HashSet<Student>(); ss.add(s1); ss.add(s2); t1.setStudents(ss); t2.setStudents(ss); // s1.setTeachers(ts); // s2.setTeachers(ts); // 增加内容完 s.save(s1); s.save(s2); s.save(t1); s.save(t2); tr.commit(); } finally { if (s != null) s.close(); } } }
说明:注意以上注释掉的内容,如果去掉会出现异常。理解:加上增加的内容后再执行发现,在开启“数据库显示”功能后,发现控制台中新增加了四条插入语句,且是插入到中间表teacher_student中,在此处相当于告诉了每个学生所关联到的老师,而如果在mysql客户端执行“show create table teacher_student”,观察它的表结构并结合“去掉注释的报错说明”,就容易理解到为什么不能有注释掉的内容。另需要说明的是“多对多”在操作和性能方面都不太理想,所以它使用较少,一般我们会选择转换成“一对多”的模型,而Hiberante的“多对多”实现,可能也是转换成两个“一对多”来实现.