说到多对多关系,印象最深刻的就是大学的选修课。**一个学生可以选修多门课程,一门课程可以有多个学生选修,学生所选的每一门课程还有成绩**。这个场景的E-R图如下:
对于多对多的关系,我们通常会抽出一张中间表(连接表),来负责维护这两张表的多对多关系,比如上述关系应该生成的表结
构为:
PO对象
Student.java
public class Student { private int id; private String name; private Set<Course> courses; //getter、setter }
Course.java
public class Course { private int id; private String name; private Set<Student> students; //getter、setter }
映射文件
Student.hbm.xml
<hibernate-mapping package="org.hibernate.test"> <class name="com.danny.hibernate.Student" table="t_student"> <id name="id"> <generator class="native" /> </id> <property name="name" /> <set name="courses" table="t_signup"> <key column="student_id"></key> <many-to-many class="com.bjpowernode.hibernate.Course" column="course_id"></many-to-many> </set> </class> </hibernate-mapping>
Course.hbm.xml
<hibernate-mapping package="org.hibernate.test"> <class name="com.danny.hibernate.Course" table="t_course"> <id name="id"> <generator class="native" /> </id> <property name="name" /> <set name="students" table="t_signup" inverse="true"> <key column="course_id"></key> <many-to-many class="com.bjpowernode.hibernate.Student" column="student_id"></many-to-many> </set> </class> </hibernate-mapping>
配置文件中的set对应于相应类中的集合,key是指向多的一方的外键,对应t_score表中的course_id。
运行代码执行的建表语句为:
alter table t_signup drop foreign key FK7DADC3438FFF3382 alter table t_signup drop foreign key FK7DADC3438CBEF332 drop table if exists t_course drop table if exists t_signup drop table if exists t_student create table t_course (id integer not null auto_increment, name varchar(255), primary key (id)) create table t_signup (student_id integer not null, course_id integer not null, primary key (student_id, course_id)) create table t_student (id integer not null auto_increment, name varchar(255), primary key (id)) alter table t_signup add index FK7DADC3438FFF3382 (student_id), add constraint FK7DADC3438FFF3382 foreign key (student_id) references t_student (id) alter table t_signup add index FK7DADC3438CBEF332 (course_id), add constraint FK7DADC3438CBEF332 foreign key (course_id) references t_course (id)
生成的表结构如下:
t_signup中生成了复合主键,student_id和course_id分别是指向t_student和t_course的外键。
**插入测试**
session.beginTransaction(); Course course1=new Course(); course1.setName("《心理应激微反应》"); session.save(course1); Course course2=new Course(); course2.setName("《哈利·波特与遗传学》"); session.save(course2); Course course3=new Course(); course3.setName("《三国杀攻略教程》"); session.save(course3); Course course4=new Course(); course4.setName("《寄生虫与寄生虫病视频欣赏》"); session.save(course4); Student student1=new Student(); Set courses1=new HashSet(); courses1.add(course1); courses1.add(course2); student1.setCourses(courses1); student1.setName("小胡"); session.save(student1); Student student2=new Student(); Set courses2=new HashSet(); courses2.add(course3); courses2.add(course4); student2.setCourses(courses2); student2.setName("小玉"); session.save(student2); Student student3=new Student(); Set courses3=new HashSet(); courses3.add(course1); courses3.add(course2); courses3.add(course3); courses3.add(course4); student3.setCourses(courses3); student3.setName("小洋"); session.save(student3); session.getTransaction().commit();
插入结果:
**查询测试**(上述配置是双向关联)
查询课程以及选修该课程的所有学生
session.beginTransaction(); Course course=(Course)session.load(Course.class, 1); System.out.println("-"+course.getName()); for(Student s:course.getStudents()){ System.out.println("--"+s.getName()); } session.getTransaction().commit();
查询结果:
Hibernate: select course0_.id as id2_0_, course0_.name as name2_0_ from t_course course0_ where course0_.id=? -《心理应激微反应》 Hibernate: select students0_.course_id as course2_1_, students0_.student_id as student1_1_, student1_.id as id0_0_, student1_.name as name0_0_ from t_signup students0_ left outer join t_student student1_ on students0_.student_id=student1_.id where students0_.course_id=? --小胡 --小洋
查询学生以及该学生所选修的所有课程
session.beginTransaction(); Course course=(Course)session.load(Course.class, 1); System.out.println("-"+course.getName()); for(Student s:course.getStudents()){ System.out.println("--"+s.getName()); } session.getTransaction().commit();
查询结果
Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_ from t_student student0_ where student0_.id=? -小胡 Hibernate: select courses0_.student_id as student1_1_, courses0_.course_id as course2_1_, course1_.id as id2_0_, course1_.name as name2_0_ from t_signup courses0_ left outer join t_course course1_ on courses0_.course_id=course1_.id where courses0_.student_id=? --《心理应激微反应》 --《哈利·波特与遗传学》
细心的你应该早就发现了,每个同学选修课程的成绩呢?
上述方法并不适合给多对多的关系添加额外的属性,那怎么办呢?可以用两个一对多关系来实现,即可以手动将中间表设计成一个实体,并为其配置映射关系,所以通常情况下,一个多对多关系也可以用两个一对多关系来实现。