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表記錄的是使用者的詳細資訊。表的結構如下:
1
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
10
CREATE 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
19
ALTER 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檔案,修改後的内容如下:
1
<? 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檔案的内容如下:
1
<? 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
@hibernate.id
34
generator - class = " foreign "
35
type = " int "
36
column = " Guid "
37
38
39
</ meta >
40
< generator class = " foreign " >
41
< param name = " property " > userBasic </ param >
42
</ generator >
43
</ id >
44
45
< property
46
name = " username "
47
type = " java.lang.String "
48
column = " Username "
49
length = " 128 "
50
>
51
< meta attribute = " field-description " >
52
@hibernate.property
53
column = " Username "
54
length = " 128 "
55
</ meta >
56
</ property >
57
< property
58
name = " gender "
59
type = " java.lang.String "
60
column = " Gender "
61
length = " 1 "
62
>
63
< meta attribute = " field-description " >
64
@hibernate.property
65
column = " Gender "
66
length = " 1 "
67
</ meta >
68
</ property >
69
< property
70
name = " birthday "
71
type = " java.sql.Date "
72
column = " Birthday "
73
length = " 19 "
74
>
75
< meta attribute = " field-description " >
76
@hibernate.property
77
column = " Birthday "
78
length = " 19 "
79
</ meta >
80
</ property >
81
82
<!-- Associations -->
83
84
<!-- bi - directional one - to - one association to UserBasic -->
85
< one - to - one
86
name = " userBasic "
87
class = " com.xxx.hibernate.UserBasic "
88
constrained = " true "
89
>
90
< meta attribute = " field-description " >
91
@hibernate.one - to - one
92
class = " com.xxx.hibernate.UserBasic "
93
constrained = " true "
94
</ meta >
95
</ one - to - one >
96
97
</ class >
98
</ hibernate - mapping >
用hbm2java生成對應的對應的Java類:hbm2java *.xml --output=xxx。
Hibernate的配置檔案hibernate.cfg.xml内容如下:
1
<? xml version="1.0" encoding="utf-8" ?>
2
<! DOCTYPE hibernate-configuration
3
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
4
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd" >
5
6
< hibernate-configuration >
7
< session-factory >
8
9
<!-- local connection properties -->
10
< property name ="hibernate.connection.url" > jdbc:mysql://127.0.0.1/xxx?useUnicode=true & characterEncoding=UTF-8 & autoReconnect=true </ property >
11
< property name ="hibernate.connection.driver_class" > com.mysql.jdbc.Driver </ property >
12
< property name ="hibernate.connection.username" > root </ property >
13
< property name ="hibernate.connection.password" > 123456 </ property >
14
<!-- property name="hibernate.connection.pool_size"></property -->
15
16
<!-- dialect for MySQL -->
17
< property name ="dialect" > net.sf.hibernate.dialect.MySQLDialect </ property >
18
19
< property name ="hibernate.show_sql" > true </ property >
20
< property name ="hibernate.use_outer_join" > true </ property >
21
< property name ="hibernate.transaction.factory_class" > net.sf.hibernate.transaction.JDBCTransactionFactory </ property >
22
23
< mapping resource ="com/xxx/hibernate/UserBasic.hbm.xml" />
24
< mapping resource ="com/xxx/hibernate/UserInfo.hbm.xml" />
25
26
</ session-factory >
27
</ hibernate-configuration >
JUnit的測試用例程式片斷如下:
1
public void testInsertUser() throws Exception
{
2
UserBasic user = new UserBasic();
3
user.setAccount("test");
4
user.setPassword("123456");
5
user.setEmail("[email protected]");
6
7
UserInfo info = new UserInfo();
8
info.setUsername("George Hill");
9
info.setGender("M");
10
info.setBirthday(new Date());
11
12
user.setUserInfo(info);
13
info.setUserBasic(user);
14
15
Transaction tx = session.beginTransaction();
16
session.save(user);
17
tx.commit();
18
}
運作測試程式,可以看到輸出了兩條insert語句。