通过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) |
|
(2) |
|
(3) |
|
(4) |
|
(5) |
|
(6) |
|
(8) |
|
(9) |
|
(10) |
|
cascade
属性允许下列值:: all
, save-update
, delete
, none
. 设置除了none
以外的其它值会传播特定的操作到关联的(子)对象中。参见后面的“Lifecycle Objects(自动管理生命周期的对象)”。
outer-join
参数允许下列三个不同值:
auto
(默认) 使用外连接抓取关联(对象),如果被关联的对象没有代理(proxy)
true
一直使用外连接来抓取关联
false
永远不使用外连接来抓取关联
一个典型的简单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) outer-join="true|false|auto"(5) property-ref="propertyNameFromAssociatedClass" (6) access="field|property|ClassName"(7) />
(1) |
|
(2) |
|
(3) |
|
(4) |
|
(5) |
|
(6) |
|
(7) |
|
有两种不同的一对一关联:
主键关联
惟一外键关联
主键关联不需要额外的表字段;两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!
比如说,对下面的Employee
和Person
进行主键一对一关联:
<one-to-one name="Person" class="Person" />
<one-to-one name="Employee" class="Employee" constrained="true" />
现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个特别的称为foreign
的NHibernate标识符生成器策略:
<class name="Person" table="PERSON"> <id name="Id" column="PERSON_ID"> <generator class="foreign"> <param name="property">Employee</param> </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>
元素把子对象的一些元素与父类对应的表的一些字段映射起来。 然后组件可以声明它们自己的属性、组件或者集合。参见后面的“Components”一章。
<component name="propertyName"(1) class="ClassName"(2) insert="true|false"(3) update="true|false"(4) access="field|property|ClassName"(5) > <parent ... /> <property ... /> <many-to-one ... /> ... <component/>
(1) |
|
(2) |
|
(3) |
|
(4) |
|
(5) |
|
其property
子标签为子类的一些属性和表字段建立映射。
<component>
元素允许加入一个 <parent>
子元素,在组件类内部就可以有一个指向其容器的实体的反向引用。
最后,多态持久化需要为父类的每个子类都进行声明。对于我们建议的“每一棵类继承树对应一个表”的策略来说,就需要使用<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) |
|
(2) |
|
(3) |
|
(4) |
|
另外一种情况,如果子类是持久化到一个属于它自己的表(每一个子类对应一个表的映射策略),那么就需要使用<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) |
|
(2) |
|
(3) |
|
(4) |
|
这种映射策略不需要指定辨别标志(discriminator)字段。但是,每一个都必须使用 <key>
元素指定一个表字段包含对象的标识符。
假设你的应用程序有两个同样名字的持久化类,但是你不想在NHibernate查询中使用他们的全限定名。除了依赖auto-import="true"
以外,类也可以被显式地“import(引用)”。你甚至可以引用没有明确被映射的类和接口。 在需要查询一个特定接口的实现类或者使用一个未映射的类在hql的查询结果中时,这种方式很有用。
<import class="System.Object, System" />
<import class="className" (1) rename="newName" (2) />
为了理解很多与持久化服务相关的.NET语言级对象的行为,我们需要把它们分为两类:
实体entity 独立于任何持有实体引用的对象。与通常的.NET模型相比,不再被引用的对象会被当作垃圾收集掉。实体必须被显式的保存和删除(除非保存和删除是从父实体向子实体引发的级联)。实体支持循环引用和交叉引用,它们也可以加上版本信息。
实体的持久化状态包含有指向其他实体的连接和一些值类型的实例。值是结构、集合、组件或者特定的不可变对象。与实体不同,值(特别是集合和组件)是通过可触及性来进行持久化和删除的。因为值对象(和结构)是随着包含它们的实体而被持久化和删除的,它们不能够被独立的加上版本信息。值没有独立的标识,所以它们不能被两个实体或者集合共享。(译者注:值还应该包含"原始类型",但文档中未提到)
所有的NHibernate类型,除了集合,都支持null语义。
直到现在,我们都一直使用"持久化对象"来代表实体。我们仍然会这么做。然而严格的来说,并不是所有用户定义的,带有持久化状态的类都是实体。组件(component)就是一个用户定义的类,仅仅由值语义构成。
基本的值类型大致可以粗糙的分为三组:System.ValueType
类型,System.Object
类型和支持大对象的System.Object
类型.和.NET类型一样,System.ValueType对应的列不能存储null
值,而System.Object可以.
表4.3 System.ValueType 映射类型
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 -忽略毫秒 |
在没有指定类型(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 |
一个 System.Enum |
潜在类型对应的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 |
|
type="TrueFalse" 必须被指定 |
YesNo |
System.Boolean |
DbType.AnsiStringFixedLength - 一个字符,'Y' 或者'N' |
type="YesNo" 必须被指定 |
表4.4 System.Object 映射类型
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 ) 属性时的默认值 |
表4.5 Large Object 映射类型
StringClob |
System.String |
DbType.String |
type="StringClob" 必须被指定.整个字段被读入内存 |
BinaryBlob |
System.Byte[] |
DbType.Binary |
type="BinaryBlob" 必须被指定. 整个字段被读入内存 |
Serializable |
任何被标记了可序列化属性(SerializableAttribute)的 |
DbType.Binary |
type="Serializable" 应该被指定. 如果不能为属性找到NHibernate类型,这是最后可依靠的类型。 |
要掌握NHibernate或者使用某种工具生成NHibernate的hbm.xml文件,应该了解这是一个NHibernate类型名的完整的层。type="integer"
被映射为Int32
NHibernateType,type="short"
被映射为Int16
NHibernateType.查看所有的转换你可以查看NHibernate.Type.TypeFactory
类的静态构造函数.
开发者创建属于他们自己的值类型也是很容易的。比如说,你可能希望持久化Int64
类型的属性,持久化成为VARCHAR
字段。NHibernate没有内置这样一种类型。自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。比如说,你可能有这样的属性:Name {get; set;}
,这是String
类型的,对应的持久化到三个字段:FIRST_NAME
, INITIAL
, SURNAME
。
要实现一个自定义类型,可以实现NHibernate.IUserType
或NHibernate.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实现。这样做的动机之一是抽象。通过自定义类型,以后假若你改变表示金额值的方法时,你的映射文件不需要更改,这就得到了保护。
你可强制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
属性,指明先前已经映射过的超类。如果你使用嵌入的资源(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>
posted on 2006-07-23 15:04 Minwell 阅读(836) 评论(3) 编辑 收藏 网摘 所属分类: Hibernate
恩楼主说的很详细,希望主楼主进一步交流!
出售蓝奇高级验证码识别引擎,可准确识别新浪动网淘宝CSDN等多种复杂验证码。
输出为一个标准DLL,可供VB,VC,Delphi,C#.NET,VB.NET,模拟精灵,按键精灵等多平台调用,调用方法简单,几行代码即可完成。独具特色的边缘检测字符分离、旋转倾斜纠正和通用字符匹配算法(无论字体和大小), 使得该引擎对于像新浪、动网、淘宝、CSDN等多种验证码均有不错的识别率,是一款效果较为理想的验证码识别引擎。附详细的调用实例和代码注释等相关技术文档。
通过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) |
|
(2) |
|
(3) |
|
(4) |
|
(5) |
|
(6) |
|
(8) |
|
(9) |
|
(10) |
|
cascade
属性允许下列值:: all
, save-update
, delete
, none
. 设置除了none
以外的其它值会传播特定的操作到关联的(子)对象中。参见后面的“Lifecycle Objects(自动管理生命周期的对象)”。
outer-join
参数允许下列三个不同值:
auto
(默认) 使用外连接抓取关联(对象),如果被关联的对象没有代理(proxy)
true
一直使用外连接来抓取关联
false
永远不使用外连接来抓取关联
一个典型的简单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) outer-join="true|false|auto"(5) property-ref="propertyNameFromAssociatedClass" (6) access="field|property|ClassName"(7) />
(1) |
|
(2) |
|
(3) |
|
(4) |
|
(5) |
|
(6) |
|
(7) |
|
有两种不同的一对一关联:
主键关联
惟一外键关联
主键关联不需要额外的表字段;两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!
比如说,对下面的Employee
和Person
进行主键一对一关联:
<one-to-one name="Person" class="Person" />
<one-to-one name="Employee" class="Employee" constrained="true" />
现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个特别的称为foreign
的NHibernate标识符生成器策略:
<class name="Person" table="PERSON"> <id name="Id" column="PERSON_ID"> <generator class="foreign"> <param name="property">Employee</param> </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>
元素把子对象的一些元素与父类对应的表的一些字段映射起来。 然后组件可以声明它们自己的属性、组件或者集合。参见后面的“Components”一章。
<component name="propertyName"(1) class="ClassName"(2) insert="true|false"(3) update="true|false"(4) access="field|property|ClassName"(5) > <parent ... /> <property ... /> <many-to-one ... /> ... <component/>
(1) |
|
(2) |
|
(3) |
|
(4) |
|
(5) |
|
其property
子标签为子类的一些属性和表字段建立映射。
<component>
元素允许加入一个 <parent>
子元素,在组件类内部就可以有一个指向其容器的实体的反向引用。