十二、组件(component),
动态组件(dynamic-component)
<component>元素把子对象的一些元素与父类对应的表的一些字段映射起来。
然后组件可以定义它们自己的属性、组件或者集合。
<component
name="PropertyName" (1)
class="ClassName" (2)
insert="true|false" (3)
upate="true|false" (4)
access="field|property|nosetter|ClassName" (5)
optimistic-lock="true|false" (6)
>
<property ...../>
<many-to-one .... />
........
</component>
说明:
(1) | name: 属性名 |
(2) |
class (可选 - |
(3) |
insert: 被映射的字段是否出现在SQL的INSERT语句中? |
(4) |
update: 被映射的字段是否出现在SQL的UPDATE语句中? |
(5) |
access可选 - 默认是 property): |
(6) |
optimistic-lock (可选 - 默认是 |
其<property>子标签为子类的一些属性与表字段之间建立映射。
<component>元素允许加入一个 <parent>子元素,在组件类内部就可以有一个指向其容器的实体的反向引用。
<dynamic-component>元素允许把一个 IDictionaryp映射为组件,其属性名对应键值。
参见第 8.5 节 “动态组件 (Dynamic components)”.
十三、子类(subclass)
最后,多态持久化需要为父类的每个子类都进行定义。 对于“每一棵类继承树对应一个表”的策略来说,就需要使用<subclass>定义。
<subclass
name="ClassName" (1)
discriminator-value="discriminator_value" (2)
proxy="ProxyInterface" (3)
lazy="true|false" (4)
dynamic-update="true|false"
dynamic-insert="true|false"><property .... />
.....
</subclass>
说明:
(1) | name: 子类的全限定名。 |
(2) |
discriminator-value (辨别标志) (可选 - |
(3) |
proxy(代理) (可选): 指定一个类或者接口,在延迟装载时作为代理使用。 |
(4) |
lazy(可选, 默认是true): 设置为 lazy="false" |
每个子类都应该定义它自己的持久化属性和子类。 <version> 和<id>属性可以从根父类继承下来。
在一棵继承树上的每个子类都必须定义一个唯一的discriminator-value。如果没有指定,就会使用.NET类的全限定名。
十四、连接的子类(joined-subclass)
此外,每个子类可能被映射到他自己的表中(每个子类一个表的策略)。被继承的状态通过和超类的表关联得到。我们使用<joined-subclass>元素。
<joined-subclass
name="ClassName" (1)
proxy="ProxyInterface" (2)
lazy="true|false" (3)
dynamic-update="true|false"
dynamic-insert="true|false"><key .... >
<property .... />
.....
</joined-subclass>
说明:
(1) | name: 子类的全限定名。 |
(2) |
proxy (可选): 指定一个类或者接口,在延迟装载时作为代理使用。 |
(3) |
lazy(可选, 默认是 true): 设置为 lazy="false" 禁止使用延迟装载。 |
这种映射策略不需要指定辨别标志(discriminator)字段。但是,每一个子类都必须使用 <key>元素指定一个表字段来持有对象的标识符。本章开始的映射可以被用如下方式重写:
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Eg"
namespace="Eg"><class name="Cat" table="CATS">
<id name="Id" column="uid" type="Int64">
<generator class="hilo"/>
</id>
<property name="BirthDate" type="Date"/>
<property name="Color" not-null="true"/>
<property name="Sex" not-null="true"/>
<property name="Weight"/>
<many-to-one name="Mate"/>
<set name="Kittens">
<key column="MOTHER"/>
<one-to-many class="Cat"/>
</set>
<joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
<key column="CAT"/>
<property name="Name" type="String"/>
</joined-subclass>
</class><class name="Dog">
<!-- mapping for Dog could go here -->
</class></hibernate-mapping>
十五、联合子类(union-subclass)
第三种选择是仅仅映射类继承树中具体类部分到表中(每个具体类一张表的策略)。 其中,每张表定义了类的所有持久化状态,包括继承的状态。 在
NHibernate 中,并不需要完全显式地映射这样的继承树。 你可以简单地使用单独的<class>定义映射每个类。
然而,如果你想使用多态关联(例如,一个对类继承树中超类的关联),你需要使用<union-subclass>映射。
<union-subclass
name="ClassName" (1)
table="tablename" (2)
proxy="ProxyInterface" (3)
lazy="true|false" (4)
dynamic-update="true|false"
dynamic-insert="true|false"
schema="schema"
catalog="catalog"
extends="SuperclassName"
abstract="true|false"
persister="ClassName"
subselect="SQL expression"
entity-name="EntityName"
node="element-name"><property .... />
.....
</union-subclass>
说明:
(1) | name: 子类的全限定名。 |
(2) |
table: 子类的表名 |
(3) |
proxy (可选): 指定一个类或者接口,在延迟装载时作为代理使用。 |
(4) |
lazy (可选, 默认是 true): 设置为 lazy="false" |
这种映射策略不需要指定辨别标志(discriminator)字段。
十六、连接(join)
使用 <join> 元素,可以将一个类的属性映射到多张表中。
当表之间存在一对一关系的时候使用。
<join
table="tablename" (1)
schema="owner" (2)
fetch="join|select" (3)
inverse="true|false" (4)
optional="true|false"> (5)<key ... />
<property ... />
...
</join>
说明:
(1) |
table: 被连接表的名称。 |
(2) |
schema (可选):覆盖由根<hibernate-mapping>元素指定的模式名称。 |
(3) |
fetch (可选 - 默认是 join): 如果设置为默认值join, |
(4) |
inverse(可选 - 默认是 false): 如果打开,NHibernate |
(5) |
optional (可选 - 默认是 false): |
例如,一个人(person)的地址(address)信息可以被映射到单独的表中(并保留所有属性的值类型语义):
<class name="Person"
table="PERSON"><id name="id" column="PERSON_ID">...</id>
<join table="ADDRESS">
<key column="ADDRESS_ID"/>
<property name="address"/>
<property name="zip"/>
<property name="country"/>
</join>
此特性常常对遗留数据模型有用,我们推荐表个数比类个数少,以及细粒度的领域模型。然而,在单独的继承树上切换继承映射策略是有用的,后面会解释这点。
十七、引用
假设你的应用程序有两个同样名字的持久化类,但是你不想在Hibernate查询中使用他们的全限定名。 除了依赖auto-import="true"以外,类也可以被显式地“import(引用)”。你甚至可以引用没有明确被映射的类和接口。
<import class="System.Object" rename="Universe"/>
<import
class="ClassName" (1)
rename="ShortName" (2)
/>
说明:
(1) |
class: 任何.NET类的全限定名。包括应用程序集名 |
(2) |
rename(可选 - 默认为类的全限定名): 在查询语句中可以使用的名字。 |
十八、实体(Entities)和值(values)
为了理解很多与持久化服务相关的.NET语言级对象的行为,我们需要把它们分为两类:
实体entity独立于任何持有实体引用的对象。与通常的.Net模型相比,
不再被引用的对象会被当作垃圾收集掉。实体必须被显式的保存和删除(除非保存和删除是从父实体向子实体引发的级联)。
这和ODMG模型中关于对象通过可触及保持持久性有一些不同——比较起来更加接近应用程序对象通常在一个大系统中的使用方法。
实体支持循环引用和交叉引用,它们也可以加上版本信息。
一个实体的持久状态包含指向其他实体和值类型实例的引用。值可以是原始类型,集合(不是集合中的对象),
组件或者特定的不可变对象。与实体不同,值(特别是集合和组件)是通过可触及性来进行持久化和删除的。
因为值对象(和原始类型数据)是随着包含他们的实体而被持久化和删除的,他们不能被独立的加上版本信息。
值没有独立的标识,所以他们不能被两个实体或者集合共享。
所有的NHibernate类型(如果.NET可空)除了集合类都支持null语义(继承System.ValueType)。
直到现在,我们都一直使用术语“持久类”(persistent class)来代表实体。我们仍然会这么做。
然而严格说来,不是所有的用户自定义的,带有持久化状态的类都是实体。组件就是用户自定义类,却是值语义的。
十九、基本值类型
基本值类型大致可以分为3类:System.ValueType类型, System.Object类型,System.Object大对象类型,像.Net的类型一样, System.ValueType类型不能存储null值,而System.Object类型可以。
表 5.3. System.ValueType映射类型
NHibernate类型 | .NET类型 | Database类型 | 备注 |
---|---|---|---|
AnsiChar | System.Char | DbType.AnsiStringFixedLength - 1 char | |
Boolean | System.Boolean | DbType.Boolean | 在没有指定类型(type) 属性时的默认值。 |
Byte | System.Byte | DbType.Byte | 在没有指定类型(type) 属性时的默认值。 |
Char | System.Char | DbType.StringFixedLength - 1 char | 在没有指定类型(type) 属性时的默认值。 |
DateTime | System.DateTime | DbType.DateTime - ignores the milliseconds | 在没有指定类型(type) 属性时的默认值。 |
Decimal | System.Decimal | DbType.Decimal | 在没有指定类型(type) 属性时的默认值。 |
Double | System.Double | DbType.Double | 在没有指定类型(type) 属性时的默认值。 |
Guid | System.Guid | DbType.Guid | 在没有指定类型(type) 属性时的默认值。 |
Int16 | System.Int16 | DbType.Int16 | 在没有指定类型(type) 属性时的默认值。 |
Int32 | System.Int32 | DbType.Int32 | 在没有指定类型(type) 属性时的默认值。 |
Int64 | System.Int64 | DbType.Int64 | 在没有指定类型(type) 属性时的默认值。 |
PersistentEnum | A System.Enum | 潜在类型对应的DbType | 不用在映射文件指定type="PersistentEnum".而是提供枚举的程序集全名, 让NHibernate用反射来猜测类型。枚举使用的潜在类型决定适当的DbType.。 |
Single | System.Single | DbType.Single | 在没有指定类型(type) 属性时的默认值。 |
Ticks | System.DateTime | DbType.Int64 | type="Ticks"必须被指定。 |
TimeSpan | System.TimeSpan | DbType.Int64 | 在没有指定类型(type) 属性时的默认值。 |
Timestamp | System.DateTime | DbType.DateTime - 取决于数据库支持 | type="Timestamp"必须被指定。 |
TrueFalse | System.Boolean | DbType.AnsiStringFixedLength- 一个字符,‘Y‘ 或者‘N‘ | type="TrueFalse"必须被指定。 |
YesNo | System.Boolean | DbType.AnsiStringFixedLength- 一个字符,‘Y‘ 或者‘N‘ | type="YesNo"必须被指定。 |
NHibernate Type | .NET Type | Database Type | Remarks |
---|---|---|---|
AnsiString | System.String | DbType.AnsiString | type="AnsiString"必须被指定。 |
CultureInfo | System.Globalization.CultureInfo | DbType.String - 表明文化(culture)的5个字符 | 在没有指定类型(type) 属性时的默认值。 |
Binary | System.Byte[] | DbType.Binary | 在没有指定类型(type) 属性时的默认值。 |
Type | System.Type | DbType.String 保存应用程序集权限定名。 | 在没有指定类型(type) 属性时的默认值。 |
String | System.String | DbType.String | 在没有指定类型(type) 属性时的默认值。 |
NHibernate Type | .NET Type | Database Type | Remarks |
---|---|---|---|
StringClob | System.String | DbType.String | type="StringClob"必须被指定。 整个字段在内存里可读。 |
BinaryBlob | System.Byte[] | DbType.Binary | type="BinaryBlob"必须被指定。 整个字段在内存里可读。 |
Serializable | Any System.Object 必须标注可序列化标签 | DbType.Binary | type="Serializable" 应该被指定. 如果不能为属性找到NHibernate类型,这是最后可依靠的类型。 |
NHibernate为了兼容Hibernate也支持也一些额外的Java类型名(主要是方便能够使用Hibernate代码生成的映射文件), tt
class="literal">type="integer"被映射为Int32 NHibernateType,type="short" 被映射为Int16 NHibernateType 。你可以通过查看NHibernate.Type.TypeFactory类的静态构造函数的代码查看到所有的上述所有的类型转换。
NHibernate之映射文件配置说明(转载3)