首页 > 技术文章 > Hibernate学习(五)Hibernate 多对多映射

daweige 2017-12-15 17:16 原文

说到多对多关系,印象最深刻的就是大学的选修课。一个学生可以选修多门课程,一门课程可以有多个学生选修,学生所选的每一门课程还有成绩。这个场景的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();

插入结果:

 

  但是上述方法并不适合给多对多的关系添加额外的属性,那怎么办呢?可以用两个一对多关系来实现,即可以手动将中间表设计成一个实体,并为其配置映射关系,所以通常情况下,一个多对多关系也可以用两个一对多关系来实现。

 

推荐阅读