您的位置:首页 > 其它

【Hibernate】一对多关联映射

2017-01-10 11:45 337 查看
    前两篇博客介绍了多对一和一对一关联映射,这篇博客介绍一对多关联映射,它的原理和多对一关联映射的原理是一样的,都是在多的一端加入一个外键,指向一的一端。下面详细介绍相关内容:

一、单向一对多

    一对多的关系我们用学生和班级来说,一个班级有多个学生,多个学生可能属于一个班级,他们的对象模型和关系模型如下:



    在进行关系映射时需要在一的一端添加<one-to-many>标签,另外还需要在一的一端(Classes)添加set属性,在映射文件中添加set标签。

classes类代码如下:

import java.util.Set;

public class Classes {

private int id;

private String name;

private Set 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 getStudents() {
return students;
}

public void setStudents(Set students) {
this.students = students;
}

}


classes.hbm.xml配置如下:

<hibernate-mapping>
<class name="com.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students">
<key column="classesid"></key>
<one-to-many class="com.hibernate.Student"></one-to-many>
</set>
</class>
</hibernate-mapping>


Student.hbm.xml代码很简单和原来的一样,如下:

<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>


需要注意的是我们在classes中添加了set属性,所以添加Student数据时应该使用hashset,插入数据代码如下:

Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();

Student student1=new Student();
student1.setName("zhangsan");
session.save(student1);

Student student2=new Student();
student2.setName("lisi");
session.save(student2);

Classes classes=new Classes();
classes.setName("ClassOne");

Set students=new HashSet();
students.add(student1);
students.add(student2);

classes.setStudents(students);
//可以成功保存数据
//但是会发出多余的update语句来维持关系,因为是一对多的原因
session.save(classes);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
读取数据代码如下:

public void testLoad1(){
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();

//获取主键为5的班级信息
Classes classes=(Classes)session.load(Classes.class,5);
//打印班级信息
System.out.println("classes.name="+classes.getName());
//设置学生集合,通过班级加载学生集合
Set students=classes.getStudents();
//迭代集合,打印集合中学生的信息
for(Iterator iter=students.iterator();iter.hasNext();){
Student student=(Student)iter.next();

System.out.println("student.name="+student.getName());
}

session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
  

    从上面的代码我们可以看出这种关系加载时的效率并不高,他需要迭代获取到的所有的学生对象。

二、双向一对多

    通过前面两篇博客的介绍我们应该可以猜到双向一对多是一种什么样的关系,双向一对多就是指它们两个的关系是双向的,就是在意的一端和多的一端同时维护关联关系,不想单向的只在一的一端维护关系。它们的关系如下:





    双向关联需要在多的一端添加一的一端的外键关联,需要在多的一端使用<many-to-one>标签,在一的一端代码和单向的是一样的,也就是Classes端的代码和单向的基本是一样的,Student配置文件添加外键列<many-to-one>标签。Student.hbm.xml代码如下:

<hibernate-mapping>
<class name="com.src.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<!-- 在多的一端Student中添加一行新的Classes列 ,并且列的名称要和Classes.hbm.xml的列明相同-->
<many-to-one name="classes" column="classesid"></many-to-one>
</class>
</hibernate-mapping>


     Classes代码和之前的代码基本一致,只是添加了inverse属性,这个属性可以用在一对多和多对多的双向关联上,inverse属性默认为false,为false表示本端可以维护关系,如果inverse为true,则本端不能维护关系,会交给另一端维护关系,本端失效。所以一对多关联映射我们通常在多的一端维护关系,让一的一端失效,所以设置为inverse为true,Classes.hbm.xml代码如下:

<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" inverse="true">
<!--
<key column="classesid" not-null="true"/>
-->
<key column="classesid"/>
<one-to-many class="com.bjpowernode.hibernate.Student"/>
</set>
</class>
</hibernate-mapping>


Student.java类需要添加classes对象属性

public class Student {

private int id;

private String name;

private Classes classes;

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 Classes getClasses() {
return classes;
}

public void setClasses(Classes classes) {
this.classes = classes;
}
}
在进行插入数据时,先插入classes和先插入Student的结果是不一样,如果先把班级信息写入数据库,再写学生,此时关系模型中的数据不会为空,如果先插入学生,再插入班级信息数据库中数据会有空的情况存在。因为他们的关系是双向的,所以即使有空的情况发生也不会报错,因此建议先插入一的数据,再插入多的数据。



在进行读取数据时因为关系是双向的,所以可以从任何一端读取另一端的信息:

session=HibernateUtils.getSession();
session.beginTransaction();

//通过班级读取学生信息
Classes classes=(Classes)session.load(Classes.class,1);
System.out.println("classes.name="+classes.getName());
Set students=classes.getStudents();

for(Iterator iter=students.iterator();iter.hasNext();){
Student student=(Student)iter.next();
System.out.println("student.name="+student.getName());
}

//通过学生信息读取班级信息
Student stu=new Student();
stu=(Student)session.load(Student.class, 1);
System.out.println("通过学生加载班级信息Classes.id= "+stu.getClasses().getId());
session.getTransaction().commit();


小结:

(1)一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端 。

(2)使用单向一对一时,因为多的一端Student不知道Classes的存在因为Student没有维护与Classes的关系,所以在保存Student的时候关系字段classesid是为null的,如果将该关系字段设置为非空,将无法保存数据,另外因为Student不维护关系,而Classes维护关系,Classes就会发出多余的update语句,保证Classes和Student有关系,这样加载Classes的时候才可以把该Classes对应的学生加载上来

(3)采用一对多双向关联映射的目的主要是为了主要是为了解决一对多单向关联的缺陷,而不是需求驱动的。注意<key>标签和<many-to-one>标签加入的字段保持一直,否则会产生数据混乱
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: