NHibernate之映射文件配置说明
1. hibernate-mapping 7.4. 组件作为联合标识符(Components as composite identifiers)第 7.4 节 “组件作为联合标识符(Components as composite identifiers)”章中说明一种更加方便的方法, 把联合标识实现为一个独立的类,下面描述的属性只对这种备用方法有效:
-
name (可选):一个组件类型,持有联合标识(参见下一节)。
-
access (可选 - 默认为property): NHibernate应该使用的访问此属性值的策略
-
class (可选 - 默认为通过反射(reflection)得到的属性类型) : 作为联合标识的组件类名(参见下一节)。
5.5 “数据库生成属性(Generated Properties)”部分的讨论。
name (可选):一个组件类型,持有联合标识(参见下一节)。
access (可选 - 默认为property): NHibernate应该使用的访问此属性值的策略
class (可选 - 默认为通过反射(reflection)得到的属性类型) : 作为联合标识的组件类名(参见下一节)。
版本号必须是以下类型:Int64, Int32, Int16, Ticks,或者 Timestamp, TimeSpan。
5.5 “数据库生成属性(Generated Properties)”的讨论。
注意
5.5 “数据库生成属性(Generated Properties)”的讨论。
typename可以是如下几种
-
NHibernate基本类型名(比如:Int32, String, Char, DateTime, Timestamp, Single, Byte[], Object, ...)。
-
一个.Net类的名字,这个类属于一种默认基础类型 (比如: System.Int16, System.Single, System.Char, System.String, System.DateTime, System.Byte[], ...)。
-
一个枚举类型的名字。(比如:. eg.Color)。
-
一个可以序列化的.NET类的名字。
-
一个自定义类型的类的名字。(比如: Illflow.Type.MyCustomType)。
注意你必须为所有类型(除了NHibernate基础类型)指定完整的应用程序集权限定名 (或者是在
NHibernate支持.NET 2.0的可空类型,这些类型和对应的非可空类型处理方式是一致的, 例如:Nullable
如果你没有指定类型,NHibernate会使用反射来得到这个名字的属性, 以此来猜测正确的NHibernate类型。NHibernate会对属性读取器(getter方法)的返回类进行解释, 按照规则2,3,4的顺序。然而,这并不足够。 在某些情况下你仍然需要type属性。 (比如,为了区别NHibernateUtil.DateTime和NHibernateUtil.Timestamp,或者为了指定一个自定义类型。)
access属性用来让你控制NHibernate如何在运行时访问属性。 在默认情况下, NHibernate会按照access-strategy.naming-strategy来格式化属性名 .naming-strategy不是必填项。
表 5.1. 访问策略
访问策略名 | 描述 |
---|---|
property |
默认实现:NHibernate访问类的set/get属性,这种方式没有命名策略,因为name就代表属性的名称。 |
field |
NHibernate将会直接访问成员变量。NHibernate使用name作为成员变量的名称。 当对象属性的get和set里面有额外的操作,而你不想让NHibernate设置或者读取对象时执行额外的操作, 可以用这个策略。当你使用HQL时需要属性名而非字段时,就需要命名策略(Naming Strateg)。 |
nosetter |
NHibernate将会在设置值时直接访问字段,获得值时访问属性。 当API使用者不能直接改变值,因而只为属性只提供了get访问器时, 你可以用这个策略。NHibernate使用name属性(attribute)作为属性(Property ), 并且需要提供字段名,所以命名策略必须(Naming Strategy)使用。 |
ClassName |
如果NHibernate内置的访问策略(Access Strategie)不能满足你的要求。 你可以通过实现NHibernate.Property.IPropertyAccessor接口来自己的访问策略(Access Strategie)。 这个值需要用程序集名(Assembly)来限定,这样就能通过 Activator.CreateInstance(string AssemblyQualifiedName)来读取。 |
命名策略(Naming Strategy)
命名策略 | 描述 |
---|---|
camelcase |
name属性被转换CamelCase格式来查找字段。 |
camelcase-underscore |
name属性被转换CamelCase格式并添加下划线前缀来查找字段。 |
lowercase |
name属性被转换小写格式来查找字段。 |
lowercase-underscore |
name属性被转换小写格式并添加下划线前缀来查找字段。 |
pascalcase-underscore |
name属性添加下划线前缀来查找字段。 |
pascalcase-m |
name属性添加字母m前缀来查找字段。 |
pascalcase-m-underscore |
name属性添加字母m和下划线前缀来查找字段。 |
十、多对一(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) fetch="join|select" (5) update="true|false" (6) insert="true|false" (6) property-ref="PropertyNameFromAssociatedClass" (7) access="field|property|nosetter|ClassName" (8) unique="true|false" (9) optimistic-lock="true|false" (10) not-found="ignore|exception" (11) />
说明:
(1) |
name:属性名。 |
(2) |
column数据库字段名 |
(3) |
class(可选 - 默认是通过反射得到属性类型): 关联的类的名字。 |
(4) |
cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。 |
(5) |
fetch (可选 - 默认为 select): 在外连接抓取(outer-join fetching)和序列选择抓取(sequential select fetching)两者中选择其一。 |
(6) |
(可选 - defaults to true) 指定对应的字段是否包含在用于UPDATE 和/或 INSERT 的SQL语句中。如果二者都是false,则这是一个纯粹的 “外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到 或者通过trigger(触发器)、或其他程序。 |
(7) |
property-ref: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。 如果没有指定,会使用对方关联类的主键。 |
(8) |
access(可选 - 默认是 property): NHibernate用来访问属性的策略。 |
(9) |
unique (可选): 使用DDL为外键字段生成一个唯一约束。此外, 这也可以用作property-ref的目标属性。这使关联同时具有 一对一的效果。 |
(10) |
optimistic-lock (可选 - 默认为 true): 指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。 换句话说,它决定这个属性发生脏数据时版本(version)的值是否增长。 |
(11) |
not-found (可选 - 默认为 exception): 指定外键引用的数据不存在时如何处理: ignore会将数据不存在作为关联到一个空对象(null)处理。 |
cascade属性允许下列值:: all, save-update, delete, none. 设置除了none以外的其它值会传播特定的操作到关联的(子)对象中。参见后面的“Lifecycle Objects(自动管理生命周期的对象)”。
fetch参数允许下列两个不同值:
-
join外连接抓取
-
select使用隔离查询抓取
一个典型的简单many-to-one 定义例子:
<many-to-one name="product" class="Product" column="PRODUCT_ID"/>
property-ref属性只应该用来对付老旧的数据库系统, 可能有外键指向对方关联表的是个非主键字段(但是应该是一个惟一关键字)的情况下。 这是一种十分丑陋的关系模型。比如说,假设Product类有一个惟一的序列号, 它并不是主键。(unique属性控制NHibernate通过SchemaExport工具生成DDL的过程。)
<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>
那么关于OrderItem 的映射可能是:
<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>
当然,我们决不鼓励这种用法。
十一、一对一
持久化对象之间一对一的关联关系是通过 one-to-one元素定义的。<one-to-one name="PropertyName" (1) class="ClassName" (2) cascade="all|none|save-update|delete" (3) constrained="true|false" (4) fetch="join|select" (5) property-ref="PropertyNameFromAssociatedClass" (6) access="field|property|nosetter|ClassName" (7) />
说明:
(1) |
name: 属性的名字。 |
(2) |
class (可选 - 默认是通过反射得到的属性类型):被关联的类的名字。 |
(3) |
cascade(级联) (可选) 表明操作是否从父对象级联到被关联的对象。 |
(4) |
constrained(约束) (可选) 表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。 这个选项影响Save()和Delete()在级联执行时的先后顺序以及 决定该关联能否被委托(也在schema export tool中被使用). |
(5) |
fetch (可选 - 默认设置为select): 在外连接抓取或者序列选择抓取选择其一. |
(6) |
property-ref: (可选) 指定关联类的属性名,这个属性将会和本类的主键相对应。如果没有指定,会使用对方关联类的主键。 |
(7) |
access (可选 - 默认是 property): NHibernate用来访问属性的策略。 |
有两种不同的一对一关联:
-
主键关联
-
惟一外键关联
主键关联不需要额外的表字段;如果两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!
比如说,对下面的Employee和Person进行主键一对一关联:
<one-to-one name="Person" class="Person"/> <one-to-one name="Employee" class="Employee" constrained="true"/>
现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个被成为foreign的特殊的现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个被成为foreign的特殊的hibernate标识符生成策略:标识符生成策略: foreign:
<class name="Person" table="PERSON"> <id name="Id" column="PERSON_ID"> <generator class="foreign"> <param name="property">Employeeparam> 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"/>
十二、组件(component), 动态组件(dynamic-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): NHibernate用来访问属性的策略。 |
(6) |
optimistic-lock (可选 - 默认是 true):表明更新此组件是否需要获取乐观锁。换句话说,当这个属性变脏时,是否增加版本号(Version |
其
十三、子类(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" 禁止使用延迟抓取。 |
每个子类都应该定义它自己的持久化属性和子类。
十四、连接的子类(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" 禁止使用延迟装载。 等价于设置proxy为自身类。 |
这种映射策略不需要指定辨别标志(discriminator)字段。但是,每一个子类都必须使用
<?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"> class> hibernate-mapping>
十五、联合子类(union-subclass)
第三种选择是仅仅映射类继承树中具体类部分到表中(每个具体类一张表的策略)。 其中,每张表定义了类的所有持久化状态,包括继承的状态。 在 NHibernate 中,并不需要完全显式地映射这样的继承树。 你可以简单地使用单独的<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 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 (可选):覆盖由根 |
(3) |
fetch (可选 - 默认是 join): 如果设置为默认值join, NHibernate 将使用一个内连接来得到这个类或其超类定义的join ,而使用一个外连接来得到其子类定义的join。如果设置为select, 则 NHibernate 将为子类定义的 join使用顺序选择。 这仅在一行数据表示一个子类的对象的时候才会发生。对这个类和其超类定义的join,依然会使用内连接得到。 |
(4) |
inverse(可选 - 默认是 false): 如果打开,NHibernate 不会插入或者更新此连接定义的属性。 |
(5) |
optional (可选 - 默认是 false): 如果打开,NHibernate 只会在此连接定义的属性非空时插入一行数据,并且总是使用一个外连接来得到这些属性。 |
例如,一个人(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类的静态构造函数的代码查看到所有的上述所有的类型转换。
二十、自定义值类型
开发者创建属于他们自己的值类型也是很容易的。比如说,你可能希望持久化Int64类型的属性, 持久化成为VARCHAR 字段。NHibernate没有内置这样一种类型。自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。 比如说,你可能有这样的属性: Name { get; set; },这是String类型的,对应的持久化到三个字段:FIRST_NAME, INITIAL, SURNAME。要实现一个自定义类型,可以实现NHibernate.UserTypes.IUserType或NHibernate.UserTypes.ICompositeUserType中的任一个, 并且使用类型的全限定类名来定义属性。请查看 NHibernate.DomainModel.DoubleStringType这个例子,看看它是怎么做的。
<property name="TwoStrings" type="NHibernate.DomainModel.DoubleStringType, NHibernate.DomainModel"> <column name="first_string"/> <column name="second_string"/> property>
注意使用
ICompositeUserType, IEnhancedUserType, INullableUserType, IUserCollectionType, 和 IUserVersionType接口为更特殊的使用方式提供支持。
你甚至可以在一个映射文件中提供参数给一个IUserType。 为了这样做, 你的UserType必须实现NHibernate.UserTypes.IParameterizedType接口。为了给自定义类型提供参数,你可以在映射文件中使用
<property name="priority"> <type name="MyCompany.UserTypes.DefaultValueIntegerType"> <param name="default">0param> type> property>
现在,IUserType 可以从传入的IDictionary对象中得到default 参数的值。
尽管 NHibernate 内建的丰富的类型和对组件的支持意味着你可能很少 需要使用自定义类型。不过, 为那些在你的应用中经常出现的(非实体)类使用自定义类型也是一个好方法。例如, 一个MonetaryAmount类使用ICompositeUserType来映射是不错的选择,虽然他可以很容易地被映射成组件。这样做的动机之一是抽象。使用自定义类型,以后假若你改变表示金额的方法时,它可以保证映射文件不需要修改。
二十一、任意(Any)类型映射
这是属性映射的又一种类型。meta-type属性使得应用程序能指定一个将数据库字段的值映射到持久化类的自定义类型。 这个持久化类包含有用id-type指定的标识符属性。 你必须指定从meta-type的值到类名的映射。
<any name="being" id-type="Int64" meta-type="string"> <meta-value value="TBL_ANIMAL" class="Animal"/> <meta-value value="TBL_HUMAN" class="Human"/> <meta-value value="TBL_ALIEN" class="Alien"/> <column name="table_name"/> <column name="id"/> any>
NHibernate也支持meta-type="class"标签,这个例子里meta-value不是必须的, 因为 meta-value就是持久化类名(persistentClass.FullName)。
<any name="being" id-type="Int64" meta-type="class"> <column name="table_name"/> <column name="id"/> any>
但你使用meta-type="class"在查询语句里设置参数时,你必须使用下面的代码:
SetParameter("paramName", typeof(YourClass).FullName, NHibernateUtil.ClassMetaType)
映射文件部分:
<any name="propertyName" (1) id-type="idtypename" (2) meta-type="metatypename" (3) cascade="cascade_style" (4) access="field|property|ClassName" (5) optimistic-lock="true|false" (6) > <meta-value ... /> <meta-value ... /> ..... <column .... /> <column .... /> ..... any>
说明:
(1) |
name: 属性名。 |
(2) |
id-type: 标识符类型。 |
(3) |
meta-type (可选 -默认是 string): 允许辨别标志(discriminator)映射的任何类型。 |
(4) |
cascade (可选 -默认是none): 级联的类型。 |
(5) |
access (可选 -默认是 property): NHibernate 用来访问属性值的策略。 |
(6) |
optimistic-lock (可选 -默认是 true): 表明更新此组件是否需要获取乐观锁。换句话说,当这个属性变脏时,是否增加版本号(Version) 。 |
二十二、SQL中引号包围的标识符
你可强制NHibernate在生成的SQL中把标识符用引号前后包围起来,这需要在映射文档中使用反向引号(`)把表名或者字段名包围(可能比较拗口,请看下面的例子)。NHibernate会使用相应的SQLDialect(方言)来使用正确的引号风格(通常是双引号,但是在SQL Server中是括号,MySQL中是反向引号)。<class name="LineItem" table="`Line Item`"> <id name="Id" column="`Item Id`"/><generator class="assigned"/>id> <property name="ItemNumber" column="`Item #`"/> ... class>
二十三、模块化映射文件
允许在独立的映射文档中定义subclass和joined-subclass,直接位于hibernate-mapping下。这就可以让你每次扩展你的类层次的时候,加入新的映射文件就行了。在子类的映射中你必须指定一个extends属性,指明先前已经映射过的超类。使用这个功能的时候,一定要注意映射文件的排序是非常重要的!<hibernate-mapping> <subclass name="Eg.Subclass.DomesticCat, Eg" extends="Eg.Cat, Eg" discriminator-value="D"> <property name="name" type="string"/> subclass> hibernate-mapping>
二十四、数据库生成属性(Generated Properties)
Generated properties指的是其值由数据库生成的属性。一般来说,如果对象有任何属性由数据库生成值,NHibernate应用程序需要进行刷新(Refresh)。但如果把属性标明为generated,就可以转由NHibernate来负责这个动作。实际上。对定义了generated properties的实体,每当NHibernate执行一条SQL INSERT或者UPDATE语句,会立刻执行一条select来获得生成的值。被标明为generated的属性还必须是 non-insertable和 non-updateable的。只有(version)(可选),时间戳 (可选)和属性可以被标明为generated。
- never (默认) 标明此属性值不是从数据库中生成。
- insert - 标明此属性值在insert的时候生成,但是不会在随后的update时重新生成。比如说创建日期就归属于这类。
- always - 标明此属性值在insert和update时都会被生成。
二十五、数据库辅助对象
帮助CREATE和DROP任意数据库对象,与NHibernate的schema交互工具组合起来,可以提供在NHibernate映射文件中完全定义用户schema的能力。虽然这是为创建和销毁trigger(触发器)或stored procedure(存储过程)等特别设计的,实际上任何可以在IDbCommand.ExecuteNonQuery()方法中执行的SQL命令都可以在此使用(比如ALTER, INSERT,等等)。本质上有两种模式来定义辅助数据库对象。第一种模式是在映射文件中显式声明CREATE和DROP命令:
<nhibernate-mapping> ... <database-object> <create>CREATE TRIGGER my_trigger ...create> <drop>DROP TRIGGER my_triggerdrop> database-object> nhibernate-mapping>
第二种模式是提供一个类,这个类知道如何组织CREATE和DROP命令。这个特别类必须实现NHibernate.Mapping.IAuxiliaryDatabaseObject接口。
<hibernate-mapping> ... <database-object> <definition class="MyTriggerDefinition, MyAssembly"/> database-object> hibernate-mapping>
你也可以在配置文件里设置参数传给数据库对象。
<hibernate-mapping> ... <database-object> <definition class="MyTriggerDefinition, MyAssembly"> <param name="parameterName">parameterValueparam> definition> database-object> hibernate-mapping>
NHibernate可以调用IAuxiliaryDatabaseObject.SetParameterValues方法接受dictionary参数。
还有,这些数据库对象可以特别指定为仅在特定的方言中才使用。
<hibernate-mapping> ... <database-object> <definition class="MyTriggerDefinition"/> <dialect-scope name="NHibernate.Dialect.Oracle9Dialect"/> <dialect-scope name="NHibernate.Dialect.OracleDialect"/> database-object> hibernate-mapping>