Hibernate中cascade

在我前面的笔记中已经写过关联关系的使用,但主要是演示,在这篇中,我将再细分析!

利用关联关系操作对象:

数据对象之间的关联关系有一对一,一对多及多对多三种。在数据库操作中,数据对象之间的关联关系使用JDBC处理很困难。例如,当删除一个班级的信息时,还要删除该班级的所有学生的基本信息。如果直接使用JDBC执行这种级联操作,会非常繁锁。Hibernate通过把实体对象之间的关联关系及级联关系在映射文件中声明,比较简单地解决了这类级联操作问题。

一对一关联关系的使用:

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

主键关联:

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

为了表示Student与Card之间的一对一的关联关系,我们需要在它们各自的映射文件 中都要使用<one-to-one>标记!

一对一关系我在前面已经写过例子程序了,在这里仅给出两个映射文件。如下:

学生PO映射信息:

(Hibernate)cascade  - 挨踢民工 - 挨踢民工

 

代码
1 <?xml version="1.0" encoding="GBK"?>
2
3  <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4
5 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
6
7
8
9  <hibernate-mapping>
10
11 <class name="hibernate.PO.TStudent" table="t_student" lazy="true"><!--把类与表关联起来 -->
12
13 <id name="id" type="java.lang.Integer">
14
15 <column name="id"/>
16
17 <generator class="increment" />
18
19 </id>
20
21 <property name="userName" type="java.lang.String">
22
23 <column name="userName" length="20" />
24
25 </property>
26
27 <property name="cardId" type="java.lang.String">
28
29 <column name="card_id" length="20" />
30
31 </property>
32
33 <property name="sex" type="java.lang.String">
34
35 <column name="sex" length="2" />
36
37 </property>
38
39 <property name="age" type="java.lang.Integer">
40
41 <column name="age" />
42
43 </property>
44
45 <one-to-one name="card" class="hibernate.PO.TCard" fetch="join" cascade="all" />
46
47 </class>
48
49 </hibernate-mapping>
50
51 <!--
52
53 class元素的lazy属性设定为true,表示延迟加载,如果lazy设为false,则
54
55 表示立即加载。以下对这二点进行说明。
56
57 立即加载:表示Hibernate在从数据库中取得数据组装好一个对象(如学生1)后,
58
59 会立即再从数据库取得数据组装此对象所关联的对象(如学生证1)。
60
61 延迟加载:表示Hibernate在从数据库中取得数据组装好一个对象(如学生1)后,
62
63 不会立即再从数据库中取得数据组装此对象所关联的对象(如学生1),
64
65 而是等到需要时,才会从数据库取得数据组装此关联对象。
66
67 <one-to-one>元素的cascade属性表明操作是否从父对象级联到被关联的对象, 它
68
69 的取得可以是以下几种:
70
71 none:在保存,删除或修改当前对象时,不对其附属对象(关联对象)进行级联
72
73 操作。它是默认值。
74
75 save-update:在保存,更新当前对象时,级联保存,更新附属对象(临时对象,
76
77 游离对象)。
78
79 delete:在删除当前对象时,级联删除附属对象。
80
81 all:所有情况下均进行级联操作,即包含save-update和delete操作。
82
83 delete-orphan:删除和当前对象解除关系的附属对象。
84
85 <one-to-one>元素的fetch属性的可选值是join和select,默认是select。
86
87 当fetch属性设定为join时,表示连接抓取(Join fetching):Hibernate通过
88
89 在Select语句中使用outer join(外连接)来获得对象的关联实例或者关联集合。
90
91 当fetch属性设定为select时,表示查询抓取(Select fetching):需要另外发
92
93 送一条Select语句抓取当前对象的关联实体或集合。-->
94

 

 

 

学生证PO映射信息:

(Hibernate)cascade  - 挨踢民工 - 挨踢民工

代码
1 <?xml version="1.0" encoding="GBK"?>
2
3 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4
5 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
6
7
8
9 <hibernate-mapping>
10
11 <class name="hibernate.PO.TCard" table="t_card" lazy="true">
12
13 <id name="id" type="java.lang.Integer">
14
15 <column name="id"/>
16
17 <generator class="foreign">
18
19 <param name="property">student</param>
20
21 </generator>
22
23 </id>
24
25 <!-- id使用外键(foreign)生成机制,引用代号为student的对象
26
27 的主键作为T_card表的主键和外键。同时student在下面的
28
29 <one-to-one>中进行了定义 -->
30
31 <property name="name" type="java.lang.String">
32
33 <column name="name" length="20" />
34
35 </property>
36
37
38
39
40
41 <one-to-one name="student" class="hibernate.PO.TStudent" constrained="true" />
42
43 <!-- constrained="true"表示Card引用了student的主键作为外键。 -->
44
45 </class>
46
47 </hibernate-mapping>
48
49

 

 外键关联:

外键关联的要点是:两个实体各自有不同的主键,但其中一个实体有一个外键引用另一个实体的主键。例如,假设,Student和Card是外键关联的一对一关系们在数据库中相应的表分别如下:t_student表有一个主键ID,t_card表有一个主键ID和一个外键student_id,此外键对应t_student表的主键ID,那么student的映射信息如上面一样不做改动,而Card的映射文件要做相应的改动。如下:

(Hibernate)cascade  - 挨踢民工 - 挨踢民工

代码
1 <hibernate-mapping>
2
3 <class name="hibernate.PO.TCard" table="t_card" lazy="true">
4
5 <id name="id" type="java.lang.Integer">
6
7 <column name="id"/>
8
9 <generator class="increment"/><!-- 不再是foreign了 -->
10
11 </id>
12
13
14
15 <property name="name" type="java.lang.String">
16
17 <column name="name" length="20" />
18
19 </property>
20
21
22
23 <many-to-one name="student" column="student_id" class="hibernate.PO.TStudent" unique="true"/>
24
25 <!-- 惟一的多对一,实际上变成一对一关系了 -->
26
27 <!-- unique设为true表示使用DDL为外键字段生成一个惟一约束。
28
29 以外键关联对象的一对一关系,其本质上已经变成了一对多的双向关联,
30
31 应直接按照一对多和多对一的要求编写它们的映射文件。当unique为
32
33 true时实际上变成了一对一的关系。 -->
34
35
36
37 </class>
38
39 </hibernate-mapping>
40
41

一对多关联关系的使用

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

单向关联:

单向的一对多关系只需要在一方进行映射配置,所以我们只配置Group的映射文件:

(Hibernate)cascade  - 挨踢民工 - 挨踢民工

代码
1 <hibernate-mapping>
2
3 <class name="hibernate.PO.Group" table="t_group" lazy="true">
4
5 <id name="id" type="java.lang.Integer">
6
7 <column name="id"/>
8
9 <generator class="increment"/>
10
11 </id>
12
13 <!-- insert属性表示被映射的字段是否出现在SQL的INSERT语句中 -->
14
15 <property name="name" type="java.lang.String" update="true" insert="true">
16
17 <column name="name" length="20" />
18
19 </property>
20
21
22
23 <!-- set元素描述的字段对应的类型为java.util.Set类型。
24
25 inverse用于表示双向关联中的被动一端。inverse的值
26
27 为false的一方负责维护关联关系。
28
29 sort排序关系,其可选值为:unsorted(不排序)。
30
31 natural(自然排序)。
32
33 comparatorClass(由某个实现了java.util.comparator接口的类型指定排序算法。)
34
35 <key>子元素的column属性指定关联表(t_student表)的外键。
36
37 -->
38
39 <set name="students"
40
41 table="t_student"
42
43 lazy="true"
44
45 inverse="false"
46
47 cascade="all"
48
49 sort="unsorted">
50
51 <key column="ID"/>
52
53 <one-to-many class="hibernate.PO.TStudent"/>
54
55 </set>
56
57 </class>
58
59 </hibernate-mapping>
60
61

 

 

双向关联:

如果要设置一对多双向关联关系,那么还需要在“多”方的映射文件中使用<many-to-one>标记。例如,在Group与Student一对多的双向关联中,除了Group的映射文件外还需要在Student的映射文件中加入如下代码:

(Hibernate)cascade  - 挨踢民工 - 挨踢民工 <many-to-one name="group"

(Hibernate)cascade  - 挨踢民工 - 挨踢民工                     class="Group"

(Hibernate)cascade  - 挨踢民工 - 挨踢民工                     cascade="none"

(Hibernate)cascade  - 挨踢民工 - 挨踢民工                     outer-join="auto"

(Hibernate)cascade  - 挨踢民工 - 挨踢民工                     update="true"

(Hibernate)cascade  - 挨踢民工 - 挨踢民工                     insert="true"

(Hibernate)cascade  - 挨踢民工 - 挨踢民工                     column="ID" />

inert和update设定是否对column属性指定的关联字段进行insert和update操作。

此外将Group.hbm.xml中<set>元素的inverse设置为true.

多对多关联关系的使用

Student(学生)和Course(课程)的关系就是多对多关系。在映射多对多关系时需要另外使用一个连接表(如Student_Course)。Student_Course表包含二个字段:courseID和studentID。此处它们的映射文件中使用<many-to-many>标记,在Student的映射文件中加入以下描述信息:

(Hibernate)cascade  - 挨踢民工 - 挨踢民工  <set name="courses" 

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               table="student_course" 

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               lazy="false" 

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               inverse="false"

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               cascade="save-update">

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               <key column="studentID" />

(Hibernate)cascade  - 挨踢民工 - 挨踢民工           <many-to-many class="Course" column="CourseID"/>    

(Hibernate)cascade  - 挨踢民工 - 挨踢民工           </set>

相应的Course的映射文件中加入以下:

(Hibernate)cascade  - 挨踢民工 - 挨踢民工 <set name="students" 

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               table="student_course" 

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               lazy="false" 

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               inverse="true"

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               cascade="save-update">

(Hibernate)cascade  - 挨踢民工 - 挨踢民工               <key column="CourseID" />

(Hibernate)cascade  - 挨踢民工 - 挨踢民工           <many-to-many class="Student" column="StudentID"/>    

(Hibernate)cascade  - 挨踢民工 - 挨踢民工           </set>

添加关联关系:

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

(Hibernate)cascade  - 挨踢民工 - 挨踢民工//获取代表Bill的Student对象

(Hibernate)cascade  - 挨踢民工 - 挨踢民工        

代码
1 Student stu = (Student)session.createQuery("from Student s where s.name='Bill'").uniqueResult();
2
3 List list = new ArrayList(stu.getCourses());
4
5 for(int i = 0 ; i < list.size(); i++)
6
7     {
8
9 Course course = (Course)list.get(i);//取得Course对象
10
11 System.out.println(course.getName());//打印出Bill所选课程的清单
12
13 }
14
15

 

 

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

(Hibernate)cascade  - 挨踢民工 - 挨踢民工//获取代表Bill的Student对象

(Hibernate)cascade  - 挨踢民工 - 挨踢民工        

代码
1 Student stu = (Student)session.createQuery("from Student s where s.name='Bill'").uniqueResult();
2
3 Course course = (Course)session.createQuery("from Course c where c.name='chemistry'").uniqueResult();
4
5 //设置stu与course的关联关系
6
7 stu.getCourses().add(course);
8
9 course.getStudents().add(stu);
10
11

 

 

删除关联关系:

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

代码
1 //获取代表Bill的Student对象
2
3 Student stu = (Student)session.createQuery("from Student s where s.name='Bill'").uniqueResult();
4
5 Course course1 = (Course)session.createQuery("from Course c where c.name='politics'").uniqueResult();
6
7 Course course2 = (Course)session.createQuery("from Course c where c.name='chemistry'").uniqueResult();
8
9 stu.getCourse().remove(course1);//删除politics课程
10
11 stu.getCourse().remove(course2);//删除chemistry课程
12
13

 

(Hibernate)cascade  - 挨踢民工 - 挨踢民工       运行以上程序将从student_course表中删除这两条记录,但T_student和T_course表没有任何变化

posted on 2010-01-07 15:42  挨踢民工  阅读(3012)  评论(0编辑  收藏  举报

导航