Hibernate的一对一联系关系实例<转>
Hibernate的一对一关联实例 Hibernate中的表的关联有一对一,一对多和多对多三种关联方式,在这篇笔记和接下来的笔记中,我将用我自己的实际例子来说明如何具体实施。
我使用的Hibernate版本是2.1.8,在Hibernate的网站2.1.6版本的中文文档中有关一对一的关联有下面一段表述:5.1.11. 一对一
持久化对象之间一对一的关联关系是通过one-to-one元素定义的。
<one-to-one
name="propertyName" (1)
class="ClassName" (2)
cascade="all|none|save-update|delete" (3)
constrained="true|false" (4)
outer-join="true|false|auto" (5)
property-ref="propertyNameFromAssociatedClass" (6)
access="field|property|ClassName" (7)
/>
(1) name: 属性的名字。
(2) class (可选 - 默认是通过反射得到的属性类型):被关联的类的名字。
(3) cascade(级联) (可选) 表明操作是否从父对象级联到被关联的对象。
(4) constrained(约束) (可选) 表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。这个选项影响save()和delete()在级联执行时的先后顺序(也在schema export tool中被使用)。
(5) outer-join(外连接) (可选 - 默认为 自动): 当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。
(6) property-ref: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。
(7) access (可选 - 默认是 property): Hibernate用来访问属性的策略。
有两种不同的一对一关联:
主键关联
惟一外键关联
主键关联不需要额外的表字段;两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!
比如说,对下面的Employee和Person进行主键一对一关联:
<one-to-one name="person" class="Person"/>
<one-to-one name="employee" class="Employee" constrained="true"/>
现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个特别的称为foreign的Hibernate标识符生成器策略:
<class name="person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="foreign">
<param name="property">employee</param>
</generator>
</id>
<one-to-one name="employee"
class="Employee"
constrained="true"/>
</class>
一个刚刚保存的Person实例被赋予和该Person的employee属性所指向的Employee实例同样的关键字值。
另一种方式是一个外键和一个惟一关键字对应,上面的Employee和Person的例子,如果使这种关联方式,应该表达成:
<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>
如果在Person的映射加入下面几句,这种关联就是双向的:
<one-to-one name"employee" class="Employee" property-ref="person"/>
下面是我的一个一对一主键关联的例子,使用的数据库是MySQL 4.1.11:
我有两个表:UserBasic和UserInfo,UserBasic记录的是用户的基本注册信息,UserInfo表记录的是用户的详细信息。表的结构如下:CREATE TABLE IF NOT EXISTS UserBasic
2(
3 Guid INT NOT NULL AUTO_INCREMENT,
4 Account VARCHAR(64) NOT NULL,
5 Password VARCHAR(16) NOT NULL,
6 Email VARCHAR(128) NOT NULL,
7 PRIMARY KEY (Guid)
8) TYPE=InnoDB;
9
10CREATE TABLE IF NOT EXISTS UserInfo
11(
12 Guid INT NOT NULL,
13 Username VARCHAR(128),
14 Gender CHAR(1),
15 Birthday DATETIME,
16 PRIMARY KEY (Guid)
17) TYPE=InnoDB;
18
19ALTER TABLE UserInfo ADD CONSTRAINT UserInfoRFUserBasic FOREIGN KEY (Guid)
20 REFERENCES UserBasic (Guid) ON DELETE CASCADE ON UPDATE RESTRICT;
UserInfo的主键值和UserBasic的主键值是一样的,两个表是单向的一对一关系。UserBasic为主控方,UserInfo是被动方。
用Middlegen生成的UserBasic.hbm.xml文件,修改后的内容如下:<?xml version="1.0"?>
2<!DOCTYPE hibernate-mapping PUBLIC
3 "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
4 "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
5
6<hibernate-mapping>
7<!--
8 Created by the Middlegen Hibernate plugin 2.1
9
10 http://boss.bekk.no/boss/middlegen/
11 http://www.hibernate.org/
12-->
13
14<class
15 name="com.xxx.hibernate.UserBasic"
16 table="UserBasic"
17 dynamic-update="true"
18 dynamic-insert="true"
19>
20 <meta attribute="class-description" inherit="false">
21 @hibernate.class
22 table="UserBasic"
23 dynamic-update="true"
24 dynamic-insert="true"
25 </meta>
26
27 <id
28 name="guid"
29 type="int"
30 column="Guid"
31 >
32 <meta attribute="field-description">
33 @hibernate.id
34 generator-class="native"
35 type="int"
36 column="Guid"
37
38
39 </meta>
40 <generator class="native" />
41 </id>
42
43 <property
44 name="account"
45 type="java.lang.String"
46 column="Account"
47 not-null="true"
48 length="64"
49 >
50 <meta attribute="field-description">
51 @hibernate.property
52 column="Account"
53 length="64"
54 not-null="true"
55 </meta>
56 </property>
57 <property
58 name="password"
59 type="java.lang.String"
60 column="Password"
61 not-null="true"
62 length="16"
63 >
64 <meta attribute="field-description">
65 @hibernate.property
66 column="Password"
67 length="16"
68 not-null="true"
69 </meta>
70 </property>
71 <property
72 name="email"
73 type="java.lang.String"
74 column="Email"
75 not-null="true"
76 length="128"
77 >
78 <meta attribute="field-description">
79 @hibernate.property
80 column="Email"
81 length="128"
82 not-null="true"
83 </meta>
84 </property>
85
86 <!-- Associations -->
87
88 <!-- bi-directional one-to-one association to UserInfo -->
89 <one-to-one
90 name="userInfo"
91 class="com.xxx.hibernate.UserInfo"
92 cascade="save-update"
93 >
94 <meta attribute="field-description">
95 @hibernate.one-to-one
96 class="com.xxx.hibernate.UserInfo"
97 cascade="save-update"
98 </meta>
99 </one-to-one>
100
101</class>
102</hibernate-mapping>
由于在建立外键的时候就声明了ON DELETE CASCADE,所以在xml的配置文件中第97行声明为save-update。如果声明为all,那么在删除UserBasic表的数据时,会无谓的多出一条删除UserInfo的delete语句出来。
UserInfo.hbm.xml文件的内容如下:<?xml version="1.0"?>
2<!DOCTYPE hibernate-mapping PUBLIC
3 "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
4 "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
5
6<hibernate-mapping>
7<!--
8 Created by the Middlegen Hibernate plugin 2.1
9
10 http://boss.bekk.no/boss/middlegen/
11 http://www.hibernate.org/
12-->
13
14<class
15 name="com.xxx.hibernate.UserInfo"
16 table="UserInfo"
17 dynamic-update="true"
18 dynamic-insert="true"
19>
20 <meta attribute="class-description" inherit="false">
21 @hibernate.class
22 table="UserInfo"
23 dynamic-update="true"
24 dynamic-insert="true"
25 </meta>
26
27 <id
28 name="guid"
29 type="int"
30 column="Guid"
31 >
32 <meta attribute="field-description">
33
文章评论