分别学习了hibernate多对一、一对多单向关联,今天来看看双向关联。
还是延续上面的学生和班级的例子。
1.基于xml的映射配置
先看实体类:
public class Student {
private int id;
private String name;
private Classes classes;
//省略了getter和setter
}
public class Classes {
private int id;
private String name;
private Set students;
//省略了getter和setter
}
再来看xml映射文件:
<!--Student的映射文件-->
<hibernate-mapping>
<class name="com.jackie.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="classes" column="classes_id"/>
</class>
</hibernate-mapping>
<!--Classes类的映射文件-->
<hibernate-mapping>
<class name="com.jackie.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" inverse="true">
<key column="classes_id"/>
<one-to-many class="com.jackie.hibernate.Student"/>
</set>
</class>
</hibernate-mapping>
由于一对多关联的缺陷,通常将一对多关系设成双向的,让多的一方来维护关系。 inverse=”true”,用了设置将维护关系的一方交给另一端,本段不再维护关系。
我们来写测试用例看一下输出:
/**
* 测试由多的一方(Student)来保存数据
*/
@Test
public void testSave3() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Classes classes = new Classes();
classes.setName("中一班");
session.save(classes);
Student student1 = new Student();
student1.setName("张三");
student1.setClasses(classes);
session.save(student1);
Student student2 = new Student();
student2.setName("李四");
student2.setClasses(classes);
//可以正常的保存数据,原因是关系交由多的一方来维护,
//也就是Student来维护
session.save(student2);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
hibernate的输出:
Hibernate: insert into t_classes (name) values (?)
Hibernate: insert into t_student (name, classesid) values (?, ?)
Hibernate: insert into t_student (name, classesid) values (?, ?)
可以正常保存数据!再来看看一的一方保存数据的情况:
/**
* 测试由一的一方(Classes)来保存数据
*/
@Test
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student1 = new Student();
student1.setName("张三");
session.save(student1);
Student student2 = new Student();
student2.setName("李四");
session.save(student2);
Classes classes = new Classes();
classes.setName("中一班");
Set students = new HashSet();
students.add(student1);
students.add(student2);
classes.setStudents(students);
//同样由于inverse=true, 一的一方已经不能完全保存数据,
//只能保存自己的数据,不能保存关联关系
session.save(classes);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
Hibernate日志输出:
Hibernate: insert into t_student (name, classesid) values (?, ?)
Hibernate: insert into t_student (name, classesid) values (?, ?)
Hibernate: insert into t_classes (name) values (?)
在看一下数据:
t_classes表:
t_student表:
可以看到,t_student表中的classesid是空的,也就是说,关系没有写入到数据库中去。这就是inverse=true的效果,强制让关系用多的一端来维护。
源代码地址
2.基于Annotation的关联配置
先看Student类的代码:
@Entity
@Table(name="t_student")
public class Student {
private int id;
private String name;
private Classes classes;
@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;
}
@ManyToOne
@JoinColumn(name="classesid")
public Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
}
Classes实体的代码:
@Entity
@Table(name="t_classes")
public class Classes {
private int id;
private String name;
private Set 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;
}
//mappedBy在哪一端,哪一端就不维护关系,它成为了关系的被管理端
//向当于hibernate中的inverse=true
//如果采用了泛型,可以不用采用targetEntity属性
@OneToMany(mappedBy="classes",targetEntity=Student.class)
@JoinColumn(name="classesid")
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}
ok,这种配置就是这样简单。测试代码同上。
源代码地址