本文的内容:
介绍NH如何处理对象间many-to-one,one-to-many和many-to-many的双向映射关系(本文主要介绍了映射文件,对于类的生成可以跟据前两篇描述的方法生成);
经验教训:
相关类图:(下面的类图包含一对一,多对一,一对多和多对多)
many-to-one:描述多对一的一种数据模型,它指定many一方是不能独立存在的,我个人认为many-to-one是NHB中保证数据有效性的最有用的一种映射,通过使用 many-to-one能有效的防治孤儿记录被写入到数据表中。在本文描述的例子中,Student类和Classes类之间是多对一关系.
通过many-to-one元素,可以定义一种常见的与另一个持久化类的关联。这种关系模型是多对一关联。(实际上是一个对象引用。)在映射文件中用many-to-one标签描述此种关系.
<
many-to-one
name
="propertyName"
(1)
column
="column_name"
(2)
class
="ClassName"
(3)
cascade
="all|none|save-update|delete"
(4)
outer-join
="true|false|auto"
(5)
update
="true|false"
(6)
insert
="true|false"
(7)
property-ref
="propertyNameFromAssociatedClass"
(8)
access
="field|property|ClassName"
(9)
unique
="true|false"
(10)
/>
1.name:属性名。指出many一方的类用哪个属性和one一方的类关联.
2.column:字段名(可选).指出many一方的类对应的数据表用哪个列和one一方的类对应的数据表关联(两表之间存在外键关联);
3.class:关联的类的名字(可选 - 默认是通过反射得到属性类型);
4.cascade:指明哪些操作会从父对象级联到关联的对象(可选).cascade属性允许下列值:: all
, save-update
, delete
, none
. 设置除了none
以外的其它值会传播特定的操作到关联的(子)对象中。
5.outer-join:当设置hibernate.use_outer_join
的时候,对这个关联允许外连接抓取(可选 - 默认为 auto
).outer-join参数允许下列三个不同值: auto(使用外连接抓取关联(对象),如果被关联的对象没有代理(proxy) ),true(一直使用外连接来抓取关联),false(永远不使用外连接来抓取关联);
6.update,insert:指定对应的字段是否在用于UPDATE
和/或 INSERT
的SQL语句中包含。如果二者都是false
,则这是一个纯粹的“外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到的,或者通过trigger(除法器),或者是其他程序(可选 - 默认为 true
)
7.property- ref:指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键(可选).property-ref属性只应该用来对付老旧的数据库系统,可能出现外键指向对方关联表的是个非主键字段(但是应该是一个惟一关键字)的情况。这是一种十分丑陋的关系模型。比如说,假设 Product类有一个惟一的序列号,它并不是主键;
8.access:NHibernate 用来访问属性的策略(可选 - 默认为property
)
9.unique:允许产生外键列唯一约束的数据库定义语言(DDL)(可选)
那么关于Student的映射可能是:
<
many-to-one
name
="Classes"
column
="cID"
unique
="true"
/>
只要在原Student.hbm.xml映射文件中添加many-to-one标签就可以了.
对于Sturent类得添加一个属性Classes:Classes
one-to-many:一对多也是一种常见的数据模型,在按范式设计的数据库中随处可见。在NHB中通过one-to-many可以非常方便的处理这种模型,同时NHB还提供了级联更新和删除的功能,以保证数据完整性。在本文描述的例子中,Classes类和Student类是一对多的关系.
Classes类的映射文件:Classes.hbm.xml
<?
xml version="1.0" encoding="utf-8"
?>
<
hibernate-mapping
xmlns
="urn:nhibernate-mapping-2.0"
>
<
class
name
="NHibernateTest.Classes,NHibernateTest"
table
="Classes"
>
<
id
name
="ClassesID"
column
="ID"
type
="Int32"
unsaved-value
="0"
>
<
generator
class
="identity"
/>
</
id
>
<
property
name
="ClassesName"
column
="ClassName"
type
="String"
length
="50"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<
bag
name
="StudentList"
cascade
="all"
inverse
="true"
>
<
key
column
="ID"
/>
<
one-to-many
class
="NHibernateTest.Student,NHibernateTest"
/>
</
bag
>
</
class
>
</
hibernate-mapping
>
如映射文件所示,one-to-many标签必须包含在标签bag中(个人理解:多嘛,就用一个包装起来~)
bag标签的name属性指出Address对象用哪个属性和Student对象关联,inverse属性使collection不更新连接(总之,这个属性提高了性能,具体的情况请参考NHibernate的帮助文档).
key标签的column属性指出了Address对象对应的数据表用哪个字段和Student对象对应的数据表关联
one-to-many标签的class属性指出了Address和哪个对象关联.
对于Classes类得创建一个StudentList : Student的属性,用来描述与Student对象的关系.
many-to-many:多对多在数据库中也是常见的数据模型,像用户与组,用户与权限等。多对多关系需要通过一个中间表实现,element的就是读取这个中间表中某列的值。在本文的例子中,Student类和Subject类是多对多的关系.
Student的映射可能是:
<
bag
name
="SubjectList"
table
="r_Student_Subject"
inverse
="true"
cascade
="save-update"
lazy
="false"
>
<
key
column
="StudentID"
/>
<
many-to-many
class
="NHibernateTest.Subject,NHibernateTest"
column
="ID"
outer-join
="auto"
/>
</
bag
>
在bag标签中,加入了一个table属性,它指定一个实现多对多的中间表
完整的Student.hbm.xml源码如下:
<?
xml version="1.0" encoding="utf-8"
?>
<
hibernate-mapping
xmlns
="urn:nhibernate-mapping-2.0"
>
<
class
name
="NHibernateTest.Student,NHibernateTest"
table
="Users"
>
<
id
name
="UserID"
column
="ID"
type
="Int32"
unsaved-value
="0"
>
<
generator
class
="identity"
/>
</
id
>
<
property
name
="UserName"
column
="UserName"
type
="String"
length
="20"
/>
<
property
name
="Password"
column
="Password"
type
="String"
length
="20"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<!--
Student类和NativePlace类是一对一的关系
-->
<
one-to-one
name
="NativePlace"
class
="NHibernateTest.NativePlace,NHibernateTest"
cascade
="all"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<!--
Student类和Classes类是多对一的关系
-->
<
many-to-one
name
="Classes"
column
="cID"
unique
="true"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<!--
Student类和Address类是一对多的关系
-->
<
bag
name
="AddressList"
cascade
="all"
inverse
="true"
>
<
key
column
="ID"
/>
<
one-to-many
class
="NHibernateTest.Address,NHibernateTest"
/>
</
bag
>
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
<!--
Student类和Subject类是多对多的关系
-->
<
bag
name
="SubjectList"
table
="r_Student_Subject"
inverse
="true"
cascade
="save-update"
lazy
="false"
>
<
key
column
="StudentID"
/>
<
many-to-many
class
="NHibernateTest.Subject,NHibernateTest"
column
="ID"
outer-join
="auto"
/>
</
bag
>
</
class
>
</
hibernate-mapping
>
Student类得添加类型为IList的属性SubjectList表示与类Subject的关系.
由于Student的映射关系比较复杂,本文就再熬述它的CRUD操作,具体的操作方法请参考本文附带的代码.