`
tanzhen-1988
  • 浏览: 51398 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

hibernate关联对象的使用

阅读更多

利用关联关系操纵对象

 

数据对象之间关联关系有一对一、一对多及多对多关联关系。在数据库操作中,数据对象之间的关联关系使用JDBC处理很困难。本节讲解如何在 Hibernate中处理这些对象之间的关联关系。本节使用到4个类,它们分别是Student(学生)、Card(学生证)、Group(班级)和 Course(课程),它们之间的关联关系如图9-1所示。这些实体存在级联(cascade)问题。例如,当删除一个班级的信息时,还要删除该班的所有 学生的基本信息。如果直接使用JDBC执行这种级联操作,会非常烦琐。Hibernate通过把实体对象之间关联关系及级联关系在映射文件中声明,比较简 便地解决了这类级联操作问题。

 

图9-1  对象关联图

 

9.2.1  一对一关联关系的使用

 

一对一关系在实际生活中是比较常见的,例如学生与学生证的关系,通过学生证可以找到学生。一对一关系在Hibernate中的实现有两种方式,分别是主键关联和外键关联。

 

1.以主键关联

 

主键关联的重点是,关联的两个实体共享一个主键值。例如,Student与Card是一对一关系,它们在数据库中对应的表分别是t_student 和t_card。它们共用一个主键值id,这个主键可由t_student表或t_card表生成。问题是如何让另一张表引用已经生成的主键值呢?例 如,t-student表填入了主键id的值,t_card表如何引用它?这需要在Hibernate的映射文件中使用主键的foreign生成机制。

 

为了表示Student与Card之间的一对一关联关系,在Student和Card的映射文件Student.hbm.xml和Card.hbm.xml中都要使用<one-to-one>标记,如例程9-2所示。

 

例程9-2  Student.hbm.xml

 

-----------------------------------------------------------------------------------------------

 

<?xml version="1.0"?>

 

<!DOCTYPE hibernate-mapping PUBLIC

 

    "-//Hibernate/Hibernate Mapping DTD//EN"

 

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

 

<hibernate-mapping>

 

<class name="test.Student" table="T_STUDENT" lazy="true"><!-- 把类与表关联起来-->

 

<id name="id" column="id" type="int">

 

<generator class="increment" />

 

</id>

 

<property name="name" column="NAME" type="string" />

 

<!--property name="card_id" column="CARD_ID" type="int" /--> <!--映射学生证号-->

 

<property name="sex" column="SEX" type="string" />

 

<property name="age" column="AGE" type="int" />

 

<one-to-one  name="card"  class="test.Card"

 

    fetch="join" cascade="all"  />

 

</class>

 

</hibernate-mapping>

 

<class>元素的lazy属性设定为true,表示延迟加载,如果lazy的值设置为false,则表示立即加载。下面对立即加载和延迟加载这两个概念进行说明。

 

l         立即加载:表示Hibernate在从数据库中取得数据,组装好一个对象(比如学生1)后,会立即再从数据库取得数据,组装此对象所关联的对象(例如学生证1)。

 

l         延迟加载:表示Hibernate在从数据库中取得数据,组装好一个对象(比如学生1)后,不会立即再从数据库取得数据,组装此对象所关联的对象(例如学生证1),而是等到需要时,才会从数据库取得数据,组装此关联对象。

 

<one-to-one>元素的cascade属性表明操作是否从父对象级联到被关联的对象,它的取值如下。

 

l         none:在保存、删除或修改对象时,不对其附属对象(关联对象)进行级联操作。这是默认设置。

 

l         save-update:在保存、更新当前对象时,级联保存、更新附属对象(临时对象、游离对象)。

 

l         delete:在删除当前对象时,级联删除附属对象。

 

l         all:在所有情况下均进行级联操作,即包含save-update和delete操作。

 

l         delete-orphan:删除和当前对象解除关系的附属对象。

 

<one-to-one>元素的fetch属性的可选值是join和select,默认值是select。当fetch属性设定为join时,表示连接抓取(Join fetching) : Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来获得对象的关联实例或者关联集合。 当fetch属性设定为select时,表示查询抓取(Select fetching):需要另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。

 

例程9-3中<one-to-one>元素的cascade属性设置为“all”,表示增加、删除及修改Student对象时,都会级联增加、删除和修改Card对象。

 

例程9-3  Card.hbm.xml

 

-----------------------------------------------------------------------------------------------

 

<?xml version="1.0"?>

 

<!DOCTYPE hibernate-mapping PUBLIC

 

    "-//Hibernate/Hibernate Mapping DTD//EN"

 

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

 

<hibernate-mapping>

 

<class name="test.Card" table="t_card" lazy="true"><!-- 把类与表关联起来-->

 

<id name="id" column="id">

 

<generator class="foreign" >

 

    <param name="property">student</param>

 

    </generator>

 

</id>

 

<one-to-one name="student"  class="test.Student" constrained="true"/>

 

<property name="name" column="name" type="string" />

 

<!-- one-to-one name="student"  class="test.Student" constrained="true"/-->

 

</class>

 

</hibernate-mapping>

 

在例程9-3中,Card.hbm.xml的主键id使用外键(foreign)生成机制,引用代号为“student”对象的主键作为Card表 的主键和外键。student在该映射文件的<one-to-one>元素中进行了定义,它是Student对象的代号。<one- to-one>元素的属性Constrained="true"表示Card引用了student的主键作为外键。

 

需要特别注意的是,Student类中要相应地加入一对get/set方法:

 

public Card getCard() {

 

    return this.card;   

 

    }

 

    public void setCard(Card card) {

 

this.card = card;

 

}

 

在Card类中也要相应地加入一对get/set方法:

 

public Student getStudent() {

 

    return this.stu;

 

    }

 

public void setStudent(Student stu) {

 

    this.stu = stu;

 

}

 

在客户端测试程序中操纵Student和Card对象的方法如例程9-4所示。

 

例程9-4  客户端测试程序

 

package test;

 

import org.hibernate.*;

 

import org.hibernate.cfg.*;

 

import java.io.File;

 

import java.util.List;

 

public class Test {

 

    public static void main(String[] args) {

 

                 

 

        File file = new File("D:\\eclipse3.2\\workspace\\HibernateTest\\hibernate.cfg.xml");

 

                 

 

        Configuration  conf = new Configuration().configure(file);

 

                 

 

        SessionFactory  sf = conf.buildSessionFactory();

 

                 

 

        Session session = sf.openSession();

 

                 

 

        Transaction tx = session.beginTransaction();

 

                 

 

        //新建Student对象

 

        Student stu = new Student();

 

            stu.setName("Walker");

 

            stu.setSex("male");

 

            stu.setAge(22);

 

            //新建Card对象

 

            Card card = new Card();

 

            card.setName("Walker");

 

                           

 

        //设置Student对象与Card对象之间的关联

 

        stu.setCard(card);

 

        card.setStudent(stu); //此句不能省略,否则card将不知从何处取得主键值

 

        

 

        try {

 

            session.save(stu);

 

        tx.commit();

 

        session.close();

 

        System.out.println("Data have been inserted into DB.");

 

        } catch (HibernateException e) {

 

            e.printStackTrace();

 

            tx.rollback();

 

        session.close();

 

        }   

 

    }

 

}

 

运行以上代码后,将会在t_student表和t_card表中插入相应的数据。

 

2.以外键关联

 

以外键关联的要点是:两个实体各自有不同的主键,但其中一个实体有一个外键引用另一个实体的主键。例如,假如Student和Card是外键关联的 一对一关系,它们在数据库中相应的表分别是t_student表和t_card表,t_student表有一个主键id,t_card表有一个主键id和 一个外键stu_id,此外键对应student表的主键id。

 

Student的映射文件Student.hmb.xml见例程9-2。但Card的映射文件Card.hbm.xml要做相应变动,如例程9-5所示。

 

例程9-5  Card.hbm.xml

 

----------------------------------------------------------------------------------------------------------------------

 

<?xml version="1.0"?>

 

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"

 

"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

 

<hibernate-mapping>

 

<class name="test.Card"  table="T_CARD" lazy= "true"><!--把类与表关联起来-->

 

<id name="id" >

 

<generator class="increment" ><!--不再是foreign了-->

 

    </generator>

 

</id>

 

<property name="name" column="NAME" type="string" />

 

<many-to-one  name="student"  class="Student" column="stu_id"

 

    unique="true"/> <!--唯一的多对一,实际上变成一对一关系了-->

 

</class>

 

</hibernate-mapping>

 

在例程9-5中,<many-to-one>元素的name属性声明外键关联对象的代号,class属性声明该外键关联对象的类,column属性声明该外键在数据表中对应的字段名,unique属性表示使用DDL为外键字段生成一个唯一约束。

 

以外键关联对象的一对一关系,其实本质上变成了一对多的双向关联了,应直接按照一对多和多对一的要求编写它们的映射文件。当<many-to-one>元素的unique属性设定为true,多对一的关系实际上变成了一对一的关系。

 

在客户端程序中操纵外键关联一对一关系的对象的方法见例程9-4。

 

9.2.2  一对多关联关系的使用

 

一对多关系很常见,例如父亲和孩子、班级与学生的关系就是很好的一对多的关系。在实际编写程序时,一对多关系有两种实现方式:单向关联和双向关联。 单向的一对多关系只需在一方进行映射配置,而双向的一对多需要在关联的双方进行映射配置。下面以Group(班级)和Student(学生)为例讲解如何 配置一对多的关系。

 

1.单向关联

 

单向的一对多关系只需在一方进行映射配置,所以我们只配置Group(班级)的映射文件Group.hbm.xml,如例程9-6所示。

 

例程9-6  Group.hbm.xml

 

<?xml version="1.0"?>

 

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"

 

"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

 

<hibernate-mapping>

 

<class name="test.Group" table="T_GROUP" lazy="true"><!--把类与表关联起来-->

 

<id name="id" column="ID"type="int">

 

<generator class="increment" >

 

    </generator>

 

</id>

 

<property name="name" column="NAME" type="string"

 

    update="true" insert="true" />

 

<set  name="students"

 

    table="T_STUDENT"

 

    lazy="false"

 

    inverse="false"

 

    cascade="all"

 

    sort="unsorted"

 

 

<key column="ID"/>

 

<one-to-many class="test.Student"/>

 

</set>

 

</class>

 

</hibernate-mapping>

 

在以上映射文件中,<property>元素的insert属性表示被映射的字段是否出现在SQL的 INSERT语句中;update属性表示被映射的字段是否出现在SQL的 UPDATE语句中。

 

<set>元素描述的字段(本例中为students)对应的类型为java.util.Set,它的各个属性的含义如下。

 

l         name:字段名,本例的字段名为students,它属于java.util.Set类型。

 

l         table:关联表名,本例中,students的关联数据表名是t_student。

 

l         lazy:是否延迟加载,lazy=false表示立即加载。

 

l         inverse:用于表示双向关联中的被动方的一端,inverse的值为false的一方负责维护关联关系。默认值为false。本例中Group将负责维护它与Student之间的关联关系。

 

l         cascade:级联关系;cascade=all表示所有情况下均进行级联操作,即包含save-update和delete操作。

 

l         sort:排序关系,其可选取值为unsorted(不排序)、natural(自然排序)、comparatorClass(由某个实现了java.util.comparator接口的类型指定排序算法)。

 

<key>子元素的column属性指定关联表(本例中t_student表)的外键,<one-to-many>子元素的class属性指定了关联类的名字。

 

此外,在Group类中增加如下get/set方法:

 

private Set students;

 

    public Set getStudents() {

 

        return this.students;

 

    }

 

    public void setStudents(Set stu) {

 

        this.students = stu;

 

}

 

假如我们想为一个班级添加一个学生对象,实现的代码如下:

 

Transaction tx = session.beginTransaction();

 

Student stu = new Student();

 

stu.setName("Walker");

 

stu.setSex("male");

 

stu.setAge(22);

 

group.getStudents().add(stu);

 

session.save(group);

 

tx.commit();

 

2.双向关联

 

如果要设置一对多双向关联,那么还需要在“多”方的映射文件中使用<many-to-one>标记。例如,在Group与 Student一对多的双向关联中,除了Group的映射文件Group.hbm.xml和Group类进行设置和修改外,还需要在Student的映射 文件Student.hbm.xm中加入:

 

<many-to-one

 

        name="group"

 

        class="test.Group"

 

        cascade="none"

 

        outer-join="auto"

 

        update="true"

 

        insert="true"

 

        column="ID"

 

        />

 

name、class等属性前面已经解释过了,这里只说明insert和update属性。insert和update设定是否对column属性指定的关联字段进行insert和update操作。在Student类还要相应添加一对get/set方法:

 

public Group getGroup() {

 

    return this.group;

 

    }

 

    public void setGroup(Group g) {

 

        this.group = g;

 

    }

 

此外,把Group.hbm.xml(如例程9-6所示)中的<set>元素的inverse属性的值设定为true,如下所示。

 

<set  name="students" table="T_STUDENT" lazy="false"

 

    inverse="true" cascade="all" sort="unsorted">

 

<key column="ID"/>

 

<one-to-many class="Student"/>

 

</set>

 

当Group.hmb.xml中<set>元素的inverse属性的值设定为false时,Group和Student之间的关联关 系由Group维护,Group负责将自己的id告诉Student,然后Hibernate发送update语句去更新记录。但现在inverse的值 设定为true后,Group和Student之间的关联关系转由Student来维护,由Student自动去取得Group的id,而这个 Student取得Group的id的动作,其实就是完成一个“学生添加到班级”的动作。

 

9.2.3  多对多关联关系的使用

 

Student(学生)和Course(课程)的关系就是多对多的关系。在映射多对多关系时,需要另外使用一个连接表(例 如,Student_Course)。Student_Course表包含2个字段:CourseId和StuId。此外,在它们的映射文件中使 用<many-to-many>标记。

 

Student的映射文件Student.hbm.xml中加入以下描述信息:

 

<set  name="courses"  table=" Student_Course" lazy="false"

 

    inverse="false" cascade="save-update" >

 

<key column="StuId"/>

 

<many-to-many class="test.Course" column="CourseId" />

 

</set>

 

相应地,Course的映射文件Course.hbm.xml加入以下描述信息:

 

<set  name="students"  table=" Student_Course" lazy="false"

 

inverse="true" cascade="save-update" >

 

<key column="CourseId"/>

 

<many-to-many class="test.Student" column="StuId"  />

 

</set>

 

1.添加关联关系

 

首先让我们编一个程序来看看一个名为Bill的学生选择了什么课程:

 

……

 

//获得包含Bill的Student对象

 

Student stu = (Student) session.createQuery(“from Student s where s.name =

 

‘Bill’ ”) .uniqueResult();

 

List ls = new ArrayList(stu.getCourses());

 

for(int i=0; i<ls.size(); i++) {

 

    Course course = (Course)ls.get(i);  //获得Course对象

 

    System.out.println(course.getName()); //打印Bill所选课程的清单

 

}

 

…..

 

现在Bill还想选修business课程,这对于程序员来说只是为Bill添加了一个到business的关联,也就是说在student_course表中新添一条记录,而T_Student 和T_Course表都不用变更。

 

……

 

Student stu = (Student) session.createQuery(“from Student s where s.name = ‘Bill’ ”) .uniqueResult();

 

Course course = (Course) session.createQuery(“from Course c where c.name =

 

‘business’ ”) .uniqueResult();

 

//设置stu与course的相互关系

 

stu.getCourses().add(course);

 

course.getStudents().add(stu);

 

…..

 

2.删除关联关系

 

删除关联关系比较简单,直接调用对象集合的remove()方法删除不要的对象即可。例如,要从学生Bill的选修课清单中删除politics和chemistry两门课,程序如下:

 

…….

 

Student stu = (Student) session.createQuery("from Student s where s.name = 'Bill' ") .uniqueResult();

 

Course course1 = (Course) session.createQuery("from Course c where c.name =

 

'politics' ") .uniqueResult();

 

Course course2 = (Course) session.createQuery("from Course c where c.name =

 

'chemistry' ") .uniqueResult();

 

stu.getCourse().remove(course1); //删除politics课程

 

stu.getCourse().remove(course2); //删除chemisty课程

 

…….

 

运行以上语句将从student_course表中删除这两条记录,但T_Student和T_Course表没有任何变化。 

 

分享到:
评论

相关推荐

    全面解读hibernate关联关系

    映射一对多关联关系 以Customer和Order为例: 一对多: 每个Customer可以有一个或者多个Order,因此Customer中应该有一个集合类型的属性,来引用所有关联的Order对象。 多对一。全实例讲解

    Hibernate ORM 对象关联关系映射初解

    NULL 博文链接:https://dreamzhong.iteye.com/blog/1205496

    hibernate各种常用关联关系的基本配置

    针对hibernate中关于对象间的关联关系的配置

    hibernate关联映射详解SSH 多对多,一对多关系对象映射

    hibernate关联映射详解SSH 多对多,一对多关系对象映射

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

    6.3 Hibernate用对象标识符(OID)来区分对象 6.4 Hibernate的内置标识符生成器的用法  6.4.1 increment标识符生成器  6.4.2 identity标识符生成器  6.4.3 sequence标识符生成器  6.4.4 hilo标识符生成器  ...

    精通hibernate:对象持久化技术孙卫琴第二版part2

    本章还将介绍通过Hibernate API来保存、修改和删除具有关联关系的对象的方法。 7.1 建立多对一的单向关联关系 148 7.1.1 [many-to-one]元素的not-null属性 153 7.1.2 级联保存和更新 155 7.2 映射一对多双向关联...

    Hibernate一对多双向自身关联demo代码

    Hibernate一对多双向自身关联demo代码

    精通Hibernate:对象持久化技术第二版part3

    本章还将介绍通过Hibernate API来保存、修改和删除具有关联关系的对象的方法。 7.1 建立多对一的单向关联关系 148 7.1.1 [many-to-one]元素的not-null属性 153 7.1.2 级联保存和更新 155 7.2 映射一对多双向关联...

    Hibernate关联映射

    在第6章简答题2员工奖项的基础上 使用连接查询完成以下功能 1&gt; 查询所有员工获得的所有奖项 并打印输出员工姓名和奖项名称 答案:cn jbit hw test Hw hw 1 2&gt; 查询所有奖项的获奖人数 并打印输出奖项...

    Hibernate对象关系

    主要说明 Hibernate 支持的各种对象关联(association)类型和集合映射,以及相应的 效果。同时看看 Hibernate 如何建立映射和如何创建表的。 我们在介绍每种关联类型时,都给出一个实例,向那些没有相关经验的读者...

    Hibernate 一对一关联查询.docx

    1、在有外键的一方,可以维护关联关系,可以建立关联关系,同样也可以解除关联关系,可以任意删除本对象,如果在hbm.xml中设置了cascade="delete",也可以删除关联对象 2、在没有外键的一方,不可以维护关联关系,...

    Hibernate查询语言HQL.PPT

    它提供了灵活多样的查询机制,包括导航对象图、通过标识符检索、使用 HQL 检索对象、使用 Hibernate 条件 API 和使用本地 SQL 查询等。 在 Hibernate 中检索对象的各种方法: 1. 导航对象图:通过对象的关联关系,...

    Hibernate 对象关系映射

    本人在厦门邦初培训时候用的ppt 快速入门文档 内容: 建立一对多的关联关系域模型 建立一对多的参照关系的模型 映射一对多关联关系 通过hibernateAPI级联操作关联对象 其它关系的映射:一对一,多对多

    Hibernate工作原理及为什么要用

    Hibernate 作为一个开放源代码的对象关系映射框架,对 JDBC 进行了轻量级的对象封装,使 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。下面将详细介绍 Hibernate 的工作原理和为什么要使用 Hibernate。 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part4

    6.3 Hibernate用对象标识符(OID)来区分对象 6.4 Hibernate的内置标识符生成器的用法  6.4.1 increment标识符生成器  6.4.2 identity标识符生成器  6.4.3 sequence标识符生成器  6.4.4 hilo标识符生成器  ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part3

    6.3 Hibernate用对象标识符(OID)来区分对象 6.4 Hibernate的内置标识符生成器的用法  6.4.1 increment标识符生成器  6.4.2 identity标识符生成器  6.4.3 sequence标识符生成器  6.4.4 hilo标识符生成器  ...

    hibernate双向一对多关联映射(XML)

    hibernate双向一对多关联映射(XML)

    精通 Hibernate:Java 对象持久化技术详解(第2版).part1.rar

    6.3 Hibernate用对象标识符(OID)来区分对象 6.4 Hibernate的内置标识符生成器的用法  6.4.1 increment标识符生成器  6.4.2 identity标识符生成器  6.4.3 sequence标识符生成器  6.4.4 hilo标识符生成器  ...

    hibernate简介及优缺点

    脱管态:将持久态对象所关联的session关闭后,该持久态对象即变为脱管态对象 二.ORM:ORM是对象到关系的映射(Object Relational Mapping),是将数据持久化的过程 1.Hibernate持久化类:Hibernate的持久化类是一个...

Global site tag (gtag.js) - Google Analytics