前面介绍了一对一、多对一和一对多的关联关系在Hibernate应如何实现,这篇博文就来介绍下最后一种关联关系:多对多。多对多关联关系在我们现实生活中的例子实在是太多太多,最典型的就是老师和学生的例子:一个老师可以教多个学生,而一个学生又可以被多个老师来教。
了解一点数据库的我们都知道,在数据库中表示多对多的关联关系,是借助于中间表来解决的。
如下:
还是和以往的思路一样,每一种关联关系都分为单向关联和双向关联,我们每种都会进行介绍,对于单向和双向关联,我们都会介绍用Annotation应如何来做,然后介绍用XXX.hbm.xml文件应如何来做。
单向关联,假设老师知道它要教多个学生,而学生并不知道他要被那些个老师教。下面就以基于这样一个假设来进行实现。
1.1 多对多单向关联关系Annotation实现
Student实体类
@Entity
public class Student {
private int id;
private String name;
@Id
@GeneratedValue
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;
}
}
Teacher类
老师知道他要教那些个学生,因此,在Teacher类中有一个Set容器。并使用注解@ManyToMany来进行修饰。
@Entity
public class Teacher {
private int id;
private String name;
private Set<Student> students=new HashSet<Student>();
@ManyToMany
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Id
@GeneratedValue
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;
}
}
这样就建立了一个多对多单向的关联关系。
在控制台我们可以看到如下的建表语句:
Hibernate给我们生成了一个Teacher_Student的中间表,中间表的字段为Teacher_id
和Student_id
.
如果我们想自己制定中间表的表名,以及中间表的字段名,该怎么办呢?
使用注解@JoinTable来解决,具体代码如下:
@Entity
public class Teacher {
private int id;
private String name;
private Set<Student> students=new HashSet<Student>();
@ManyToMany
@JoinTable(name = "T_S",//设置中间表的名字,以及中间表的字段名
joinColumns = {@JoinColumn(name="teacher_id")},
inverseJoinColumns = @JoinColumn(name="student_id")
)
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Id
@GeneratedValue
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;
}
}
测试结果如下:
1.2 多对多单向关联关系XXX.hbm.xml实现
这里主要看下两个xml文件。
Teacher.hbm.xml
关键点在这里:
<set name="students" table="T_S" > <!-- 指定表名为T_S -->
<!-- key中 这个column指向的是Teacher这个表的外键名称,下面是指向另一外一个表的外键名称 -->
<key column="teacher_id"></key>
<many-to-many class="com.hibernate.model.Student" column="student_id"/>
</set>
完整内容如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="Teacher" table="teacher" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
<set name="students" table="T_S" > <!-- 指定表名为T_S -->
<!-- key中 这个column指向的是Teacher这个表的外键名称,下面是指向另一外一个表的外键名称 -->
<key column="teacher_id"></key>
<many-to-many class="com.hibernate.model.Student" column="student_id"/>
</set>
</class>
</hibernate-mapping>
Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="Student" table="student" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
</class>
</hibernate-mapping>
这样就是采用了xml文件实现了多对多单向关联关系。
2.1 多对多双向关联关系Annotation实现
在代码中,Student类和Teacher类都会有一个对方的Set容器,来表示每个学生知道有那几个老师教他们,每个老师知道他们需要教那几个学生。
Teacher类的代码不变
@Entity
public class Teacher {
private int id;
private String name;
private Set<Student> students=new HashSet<Student>();
@ManyToMany
@JoinTable(name = "T_S",//设置中间表的名字,以及中间表的字段名
joinColumns = {@JoinColumn(name="teacher_id")},
inverseJoinColumns = @JoinColumn(name="student_id")
)
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Id
@GeneratedValue
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;
}
}
Student类有一定变化,相比多对多单向关联
由于在Teacher类中,已经设置了关联,这边使用@ManyToMany(mappedBy = “students”)即可
@Entity
public class Student {
private int id;
private String name;
private Set<Teacher> teachers=new HashSet<Teacher>();
@ManyToMany(mappedBy = "students")
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
@Id
@GeneratedValue
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;
}
}
这样,就使用Annotation完成了多对多的双向关联。
2.2 多对多双向关联关系XXX.hbm.xml实现
主要涉及到的两个xml文件。
1、Teacher.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="Teacher" table="teacher" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
<set name="students" table="T_S" > <!-- 指定表名为T_S -->
<!-- key中 这个column指向的是Teacher这个表的外键名称,下面是指向另一外一个表的外键名称 -->
<key column="teacher_id"></key>
<many-to-many class="com.hibernate.model.Student" column="student_id"/>
</set>
</class>
</hibernate-mapping>
2、Student.hbm.xml
Student.hbm.xml文件与Teacher.hbm.xml文件基本一样。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="Student" table="student" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
<set name="teachers" table="T_S" > <!-- 指定表名为T_S -->
<!-- key中 这个column指向的是Teacher这个表的外键名称,下面是指向另一外一个表的外键名称 -->
<key column="student_id"></key>
<many-to-many class="com.hibernate.model.Teacher" column="teacher_id"/>
</set>
</class>
</hibernate-mapping>
这样,就完成了多对多关系的关联。
在上面的学习过程中,多对多关联关系不难,借助于Hibernate还是比较好实现,至于如何来写注解的XXX.hbm.xml文件,我们都不需要记,会查文档就行,这里,提供一个Hibernate Annotation的文档连接:http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/