Hibernate学习(五)Hibernate 多对多映射
说到多对多关系,印象最深刻的就是大学的选修课。一个学生可以选修多门课程,一门课程可以有多个学生选修,学生所选的每一门课程还有成绩。这个场景的E-R图如下:
对于多对多的关系,我们通常会抽出一张中间表(连接表),来负责维护这两张表的多对多关系,比如上述关系应该生成的表结构为:
PO对象
Student.java
package entity; import java.util.Set; public class Students { private int id ; private String name; private Set<Course>courses; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Course> getCourses() { return courses; } public void setCourses(Set<Course> courses) { this.courses = courses; } }
Course.java
package entity; import java.util.Set; public class Course { private int id; private String name; private Set<Students> students; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Students> getStudents() { return students; } public void setStudents(Set<Students> students) { this.students = students; } }
映射文件
Students.hnm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name ="entity.Students" table="t_students"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="Courses" table="t_singup"> <key column="student_id"/> <!-- 多个学生id对应对个course_id -->
<many-to-many class="entity.Course" column="course_id"></many-to-many> </set> </class> </hibernate-mapping>
配置文件中的set对应于相应类中的集合,key是指向多的一方的外键,对应t_score表中的course_id。
Course.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="entity.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"/> <many-to-many class="entity.Students" column="student_id"/> </set> </class> </hibernate-mapping>
运行代码执行的建表语句为:
drop table t_course drop table t_signup drop table t_students create table t_course (id integer primary key , name varchar(255)); create sequence course minvalue 1 --最小值 nomaxvalue --不设置最大值 start with 1 --从1开始计数 increment by 1 --每次加1个 nocycle --一直累加,不循环 nocache --不建缓冲区 create or replace trigger course_tg before insert on t_course for each row when(new.id is null) begin select course.nextval into:new.id from dual; end; create table t_signup (student_id integer , course_id integer ,constraint zhujian primary key (student_id, course_id)); drop sequence students; create table t_students (id integer , name varchar(255), primary key (id)); create sequence students minvalue 1 --最小值 nomaxvalue --不设置最大值 start with 1 --从1开始计数 increment by 1 --每次加1个 nocycle --一直累加,不循环 nocache ;--不建缓冲区 create or replace trigger students_tg before insert on t_students for each row when(new.id is null) begin select students.nextval into:new.id from dual; end; create index FK7DADC3438FFF3382 on t_signup(student_id); alter table t_signup add constraint FK7DADC3438FFF3382 foreign key(student_id) references t_students(id); create index FK7DADC3438CBEF332 on t_signup(course_id); alter table t_signup add constraint FK7DADC3438CBEF332 foreign key(course_id) references t_course(id);
生成的表结构如下:
t_signup中生成了复合主键,student_id和course_id分别是指向t_students和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();
插入结果:
但是上述方法并不适合给多对多的关系添加额外的属性,那怎么办呢?可以用两个一对多关系来实现,即可以手动将中间表设计成一个实体,并为其配置映射关系,所以通常情况下,一个多对多关系也可以用两个一对多关系来实现。