Hibernate2.1.8中有关一对多的文档,可以查看官方网站上的文档:http://www.hibernate.org/hib_docs/reference/zh-cn/html/,由于篇幅太长,这里就不再引用。
我的例子是一个全国省和市的数据表,省为一个表,市为一个表,所使用的数据库是MySQL 4.1.11。表的结构如下:
1
CREATE
TABLE
IF
NOT
EXISTS
Province
2
(
3
Guid
INT
NOT
NULL
AUTO_INCREMENT,
4
Provincename
VARCHAR
(
16
)
NOT
NULL
,
5
PRIMARY
KEY
(Guid)
6
) TYPE
=
InnoDB;
7

8
CREATE
TABLE
IF
NOT
EXISTS
City
9
(
10
Guid
INT
NOT
NULL
AUTO_INCREMENT,
11
Cityname
VARCHAR
(
32
)
NOT
NULL
,
12
ProvinceID
INT
NOT
NULL
,
13
PRIMARY
KEY
(Guid)
14
) TYPE
=
InnoDB;
15

16
ALTER
TABLE
City
ADD
CONSTRAINT
CityRFProvince
FOREIGN
KEY
(ProvinceID)
17
REFERENCES
Province (Guid)
ON
DELETE
CASCADE
ON
UPDATE
RESTRICT
;
Province表做为主控方,City表做为被控方,两者之间是双向的一对多关系。用Middlegen生成的Province.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.Province"
16
table
="Province"
17
>
18
<
meta
attribute
="class-description"
inherit
="false"
>
19
@hibernate.class
20
table="Province"
21
</
meta
>
22

23
<
id
24
name
="guid"
25
type
="int"
26
column
="Guid"
27
>
28
<
meta
attribute
="field-description"
>
29
@hibernate.id
30
generator-class="native"
31
type="int"
32
column="Guid"
33

34

35
</
meta
>
36
<
generator
class
="native"
/>
37
</
id
>
38

39
<
property
40
name
="provincename"
41
type
="java.lang.String"
42
column
="Provincename"
43
not-null
="true"
44
length
="16"
45
>
46
<
meta
attribute
="field-description"
>
47
@hibernate.property
48
column="Provincename"
49
length="16"
50
not-null="true"
51
</
meta
>
52
</
property
>
53

54
<!--
Associations
-->
55
56
<!--
bi-directional one-to-many association to City
-->
57
<
set
58
name
="cities"
59
lazy
="true"
60
inverse
="true"
61
cascade
="save-update"
62
>
63
<
meta
attribute
="field-description"
>
64
@hibernate.set
65
lazy="true"
66
inverse="true"
67
cascade="save-update"
68

69
@hibernate.collection-key
70
column="ProvinceID"
71

72
@hibernate.collection-one-to-many
73
class="com.xxx.hibernate.City"
74
</
meta
>
75
<
key
>
76
<
column
name
="ProvinceID"
/>
77
</
key
>
78
<
one-to-many
79
class
="com.xxx.hibernate.City"
80
/>
81
</
set
>
82

83
</
class
>
84
</
hibernate-mapping
>
85
set节点有以下属性(摘自Hibernate文档):
(1) | name 集合属性的名称 |
(2) | table (可选——默认为属性的名称)这个集合表的名称(不能在一对多的关联关系中使用) |
(3) | schema (可选) 表的schema的名称, 他将覆盖在根元素中定义的schema |
(4) | lazy (可选——默认为false) lazy(可选--默认为false) 允许延迟加载(lazy initialization )(不能在数组中使用) |
(5) | inverse (可选——默认为false) 标记这个集合作为双向关联关系中的方向一端。 |
(6) | cascade (可选——默认为none) 让操作级联到子实体 |
(7) | sort(可选)指定集合的排序顺序, 其可以为自然的(natural)或者给定一个用来比较的类。 |
(8) | order-by (可选, 仅用于jdk1.4) 指定表的字段(一个或几个)再加上asc或者desc(可选), 定义Map,Set和Bag的迭代顺序 |
(9) | where (可选) 指定任意的SQL where条件, 该条件将在重新载入或者删除这个集合时使用(当集合中的数据仅仅是所有可用数据的一个子集时这个条件非常有用) |
(10) | outer-join(可选)指定这个集合,只要可能,应该通过外连接(outer join)取得。在每一个SQL语句中, 只能有一个集合可以被通过外连接抓取(译者注: 这里提到的SQL语句是取得集合所属类的数据的Select语句) |
(11) | batch-size (可选, 默认为1) 指定通过延迟加载取得集合实例的批处理块大小("batch size")。 |
(12) | access(可选-默认为属性property):Hibernate取得属性值时使用的策略 |
由于在建立外键的时候就声明了ON DELETE CASCADE,所以在xml的配置文件中cascade声明为save-update。如果声明为all,那么在删除Province表的数据时,会无谓的多出一条删除City的delete语句出来,这将会影响程序的性能。
City.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.City"
16
table
="City"
17
>
18
<
meta
attribute
="class-description"
inherit
="false"
>
19
@hibernate.class
20
table="City"
21
</
meta
>
22

23
<
id
24
name
="guid"
25
type
="int"
26
column
="Guid"
27
>
28
<
meta
attribute
="field-description"
>
29
@hibernate.id
30
generator-class="native"
31
type="int"
32
column="Guid"
33

34

35
</
meta
>
36
<
generator
class
="native"
/>
37
</
id
>
38

39
<
property
40
name
="cityname"
41
type
="java.lang.String"
42
column
="Cityname"
43
not-null
="true"
44
length
="32"
45
>
46
<
meta
attribute
="field-description"
>
47
@hibernate.property
48
column="Cityname"
49
length="32"
50
not-null="true"
51
</
meta
>
52
</
property
>
53

54
<!--
Associations
-->
55
56
<!--
bi-directional many-to-one association to Province
-->
57
<
many-to-one
58
name
="province"
59
class
="com.xxx.hibernate.Province"
60
cascade
="none"
61
outer-join
="auto"
62
update
="true"
63
insert
="true"
64
access
="property"
65
not-null
="true"
66
>
67
<
meta
attribute
="field-description"
>
68
@hibernate.many-to-one
69
cascade="none"
70
outer-join="auto"
71
update="true"
72
insert="true"
73
access="property"
74
not-null="true"
75
@hibernate.column name="ProvinceID"
76
</
meta
>
77
<
column
name
="ProvinceID"
/>
78
</
many-to-one
>
79

80
</
class
>
81
</
hibernate-mapping
>
82
many-to-one节点有以下属性(摘自Hibernate文档):
(1) | name: 属性名。 |
(2) | column (可选): 字段名。 |
(3) | class (可选 - 默认是通过反射得到属性类型): 关联的类的名字。 |
(4) | cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。 |
(5) | outer-join(外连接) (可选 - 默认为 自动): 当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。 |
(6) | update, insert (可选 - defaults to true) 指定对应的字段是否在用于UPDATE 和/或 INSERT的SQL语句中包含。如果二者都是false,则这是一个纯粹的“外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到的,或者通过trigger(除法器),或者是其他程序。 |
(7) | property-ref: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。 |
(8) | access (可选 - 默认是 property): Hibernate用来访问属性的策略。 |
cascade 属性允许下列值: all, save-update, delete, none。设置除了none以外的其它值会传播特定的操作到关联的(子)对象中。参见后面的“Lifecycle Objects(自动管理生命周期的对象)”。
outer-join参数允许下列三个不同值:
用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/City.hbm.xml"
/>
24
<
mapping
resource
="com/xxx/hibernate/Province.hbm.xml"
/>
25

26
</
session-factory
>
27
</
hibernate-configuration
>
JUnit的测试用例程序片断如下:
1
public
void
testInsert()
{
2
try
{
3
Province province = new Province();
4
province.setProvincename("广东");
5
6
City city = new City();
7
city.setCityname("深圳");
8
9
city.setProvince(province);
10
province.setCities(new HashSet());
11
province.getCities().add(city);
12
13
Transaction tx = session.beginTransaction();
14
session.save(province);
15
tx.commit();
16
} catch (HibernateException e)
{
17
e.printStackTrace();
18
} catch (Exception ex)
{
19
ex.printStackTrace();
20
}
21
}
运行测试程序,可以看到输出了两条insert语句,省的值和市的值都插入到了表中。