O/R Mapping基础(续二)

子类(subclass)

最后,多态持久化需要为父类的每个子类都进行声明。对于我们建议的“每一棵类继承树对应一个表”的策略来说,就需要使用<subclass>声明。

<subclass
name="ClassName"(1)
discriminator-value="discriminator_value"(2)
proxy="ProxyInterface"(3)
dynamic-update="true|false"
dynamic-insert="true|false"
extends="BaseMappedClassName"> (4)
<property ... / >
...
<subclass/>
(1)

name: 子类的全限定名。

(2)

discriminator-value (可选 - 默认为类名): 一个用于区分每个独立的子类的值。

(3)

proxy (可选):指定一个类或者接口,在延迟装载时作为代理使用。

(4)

extends (可选):指定这个子类继承的映射类。只有在使用模块化映射文件(Modular Mapping Files) 时才需要被用到。

连接的子类(joined-subclass)

另外一种情况,如果子类是持久化到一个属于它自己的表(每一个子类对应一个表的映射策略),那么就需要使用<joined-subclass>元素。

<joined-subclass
name="ClassName"(1)
table="tableName" (2)
proxy="ProxyInterface"(3)
dynamic-update="true|false"
dynamic-insert="true|false"
extends="BaseMappedClassName"> (4)
<key ... >
<property ... / >
...
<joined-subclass/>
(1)

name: 子类的全限定名。

(2)

table:包含特殊类数据的表名。

(3)

proxy (可选):指定一个类或者接口,在延迟装载时作为代理使用。

(4)

extends (可选):指定这个子类继承的映射类。只有在使用模块化映射文件(Modular Mapping Files) 时才需要被用到。

这种映射策略不需要指定辨别标志(discriminator)字段。但是,每一个都必须使用 <key>元素指定一个表字段包含对象的标识符。

map, set, list, bag

集合类在后面讨论。

引用(import)

假设你的应用程序有两个同样名字的持久化类,但是你不想在NHibernate查询中使用他们的全限定名。除了依赖auto-import="true"以外,类也可以被显式地“import(引用)”。你甚至可以引用没有明确被映射的类和接口。 在需要查询一个特定接口的实现类或者使用一个未映射的类在hql的查询结果中时,这种方式很有用。

<import class="System.Object, System" />
<import
class="className" (1)
rename="newName"  (2)
/>
(1)

class: 任何.NET类的全限定名(或接口)。

(2)

rename (可选 - 默认为类的全限定名): 在查询语句中可以使用的名字。

NHibernate 的类型

实体(Entities)和值(values)

为了理解很多与持久化服务相关的.NET语言级对象的行为,我们需要把它们分为两类:


实体entity 独立于任何持有实体引用的对象。与通常的.NET模型相比,不再被引用的对象会被当作垃圾收集掉。实体必须被显式的保存和删除(除非保存和删除是从父实体向子实体引发的级联)。实体支持循环引用和交叉引用,它们也可以加上版本信息。

实体的持久化状态包含有指向其他实体的连接和一些类型的实例。值是结构、集合、组件或者特定的不可变对象。与实体不同,值(特别是集合和组件)是通过可触及性来进行持久化和删除的。因为值对象(和结构)是随着包含它们的实体而被持久化和删除的,它们不能够被独立的加上版本信息。值没有独立的标识,所以它们不能被两个实体或者集合共享。(译者注:值还应该包含"原始类型",但文档中未提到)

所有的NHibernate类型,除了集合,都支持null语义。

直到现在,我们都一直使用"持久化对象"来代表实体。我们仍然会这么做。然而严格的来说,并不是所有用户定义的,带有持久化状态的类都是实体。组件(component)就是一个用户定义的类,仅仅由值语义构成。

基本值类型(Basic value types)

基本的值类型大致可以粗糙的分为三组:System.ValueType类型,System.Object类型和支持大对象的System.Object类型.和.NET类型一样,System.ValueType对应的列不能存储null值,而System.Object可以.

表4.3 System.ValueType 映射类型

NHibernate 类型.NET 类型Database 类型备注
BooleanSystem.BooleanDbType.Boolean在没有指定类型(type) 属性时的默认值
ByteSystem.ByteDbType.Byte在没有指定类型(type) 属性时的默认值
CharSystem.CharDbType.StringFixedLength - 1 char在没有指定类型(type) 属性时的默认值
DateTimeSystem.DateTimeDbType.DateTime -忽略毫秒在没有指定类型(type) 属性时的默认值
DecimalSystem.DecimalDbType.Decimal在没有指定类型(type) 属性时的默认值
DoubleSystem.DoubleDbType.Double在没有指定类型(type) 属性时的默认值
GuidSystem.GuidDbType.Guid在没有指定类型(type) 属性时的默认值
Int16System.Int16DbType.Int16在没有指定类型(type) 属性时的默认值
Int32System.Int32DbType.Int32在没有指定类型(type) 属性时的默认值
Int64System.Int64DbType.Int64在没有指定类型(type) 属性时的默认值
PersistentEnum一个 System.Enum潜在类型对应的DbType

不用在映射文件指定type="PersistentEnum".而是提供枚举的程序集全名,让NHibernate用反射来猜测类型。枚举使用的潜在类型决定适当的DbType

SingleSystem.SingleDbType.Single在没有指定类型(type) 属性时的默认值
TicksSystem.DateTimeDbType.Int64type="Ticks"必须被指定
TimeSpanSystem.TimeSpanDbType.Int64在没有指定类型(type) 属性时的默认值
TimestampSystem.DateTimeDbType.DateTime - 取决于数据库支持type="Timestamp"必须被指定
TrueFalseSystem.Boolean

DbType.AnsiStringFixedLength - 一个字符,'T' 或者'F'

type="TrueFalse" 必须被指定
YesNoSystem.BooleanDbType.AnsiStringFixedLength - 一个字符,'Y' 或者'N'type="YesNo"必须被指定

表4.4 System.Object 映射类型

NHibernate 类型.NET 类型Database 类型备注
AnsiStringSystem.StringDbType.AnsiStringtype="AnsiString"必须被指定
CultureInfoSystem.Globalization.CultureInfoDbType.String - 表明文化(culture)的5个字符在没有指定类型(type) 属性时的默认值
BinarySystem.Byte[]DbType.Binary在没有指定类型(type) 属性时的默认值
TypeSystem.TypeDbType.String 容纳程序集全名在没有指定类型(type) 属性时的默认值
StringSystem.StringDbType.String在没有指定类型(type) 属性时的默认值

表4.5 Large Object 映射类型

NHibernate 类型.NET 类型Database 类型备注
StringClobSystem.StringDbType.Stringtype="StringClob" 必须被指定.整个字段被读入内存
BinaryBlobSystem.Byte[]DbType.Binarytype="BinaryBlob" 必须被指定. 整个字段被读入内存
Serializable

任何被标记了可序列化属性(SerializableAttribute)的System.Object.

DbType.Binarytype="Serializable" 应该被指定. 如果不能为属性找到NHibernate类型,这是最后可依靠的类型。

要掌握NHibernate或者使用某种工具生成NHibernate的hbm.xml文件,应该了解这是一个NHibernate类型名的完整的层。type="integer"被映射为Int32NHibernateType,type="short"被映射为Int16NHibernateType.查看所有的转换你可以查看NHibernate.Type.TypeFactory类的静态构造函数.

自定义值类型(Custom value types)

开发者创建属于他们自己的值类型也是很容易的。比如说,你可能希望持久化Int64类型的属性,持久化成为VARCHAR字段。NHibernate没有内置这样一种类型。自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。比如说,你可能有这样的属性:Name {get; set;} ,这是String类型的,对应的持久化到三个字段:FIRST_NAME, INITIAL, SURNAME

要实现一个自定义类型,可以实现NHibernate.IUserTypeNHibernate.ICompositeUserType中的任一个,并且使用类型的全限定类名来声明属性。请查看NHibernate.DomainModel.DoubleStringType这个例子,看看它是怎么做的。

<property name="TwoStrings" type="NHibernate.DomainModel.DoubleStringType, NHibernate.DomainModel">
<column name="first_string"/>
<column name="second_string"/>
</property>

注意使用<column>标签来把一个属性映射到多个字段的做法。

虽然NHibernate内置的丰富类型和对component的支持意味着你可能很少需要使用自定义类型,至少对于你程序中经常出现的自定义类(并非实体)来说,这是一种好方法。比如说,MonetoryAmount(价格总额)对比使用ICompositeUserType来说更好,虽然它可以很容易的使用一个component实现。这样做的动机之一是抽象。通过自定义类型,以后假若你改变表示金额值的方法时,你的映射文件不需要更改,这就得到了保护。

映射到"任意"(any)类型

TODO

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>

映射文件的模块化(Modular mapping files)

允许在独立的映射文档中定义subclassjoined-subclass,直接位于hibernate-mapping下。这就可以让你每次扩展你的类层次的时候,加入新的映射文件就行了。在子类的映射中你必须指定一个extends属性,指明先前已经映射过的超类。如果你使用嵌入的资源(Embedded Resources)配置NHibernate, hbm.xml文件会自动配置为正确的顺序.如果手动添加或者在cfg.xml文件中指定它们,映射文件的排序是非常重要的!

<hibernate-mapping>
<subclass name="Eg.Subclass.DomesticCat, Eg" extends="Eg.Cat, Eg" discriminator-value="D">
<property name="Name" type="String"/>
</subclass>
</hibernate-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值