O/R Mapping基础(续一)

多对一(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: 属性名。

(2)

column (可选):字段名。

(3)

class (可选 - 默认是通过反射得到属性类型): 关联的类的名字。

(4)

cascade (可选): 指明哪些操作会从父对象级联到关联的对象。

(5)

outer-join (可选 - 默认为 auto): 当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。

(6)

update, insert (可选 - 默认为 true)指定对应的字段是否在用于UPDATE 和/或 INSERT的SQL语句中包含。如果二者都是false,则这是一个纯粹的“外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到的,或者通过trigger(除法器),或者是其他程序。

(8)

property-ref: (可选)指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。

(9)

access (可选 - 默认为property): NHibernate 用来访问属性的策略。

(10)

unique (可选):允许产生外键列唯一约束的数据库定义语言(DDL)。

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元素定义的。

<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)

name: 属性的名字

(2)

class (可选 - 默认是通过反射得到的属性类型): 被关联的类的名字.

(3)

cascade (可选) 表明操作是否从父对象级联到被关联的对象。

(4)

contstrainted (可选) 表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。这个选项影响Save()Delete()在级联执行时的先后顺序(也在schema export tool中被使用)。

(5)

outer-join (可选 - 默认为 auto):当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。

(6)

property-ref: (可选): 指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。

(7)

access (可选 - defaults to property): NHibernate 用来访问属性的策略。

有两种不同的一对一关联:

  • 主键关联

  • 惟一外键关联

主键关联不需要额外的表字段;两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!

比如说,对下面的EmployeePerson进行主键一对一关联:

<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实例被赋予和该PersonEmployee属性所指向的Employee实例同样的关键字值。

另一种方式是一个外键和一个惟一关键字对应,上面的EmployeePerson的例子,如果使这种关联方式,应该表达成:

<many-to-one name="Person" class="Person" column="PERSON_ID" unique="true" />

如果在Person的映射加入下面几句,这种关联就是双向的:

<one-to-one name="Employee" class="Employee" property-ref="Person" />

组件(component)

<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)

name: 属性名

(2)

class (可选 - 默认为通过反射得到的属性类型): 组件(子)类的名字。

(3)

insert: 被映射的字段是否出现在SQL的INSERT语句中?

(4)

update: 被映射的字段是否出现在SQL的UPDATE语句中?

(5)

access (可选 - 默认是 property): NHibernate用来访问属性的策略。

property子标签为子类的一些属性和表字段建立映射。

<component>元素允许加入一个 <parent>子元素,在组件类内部就可以有一个指向其容器的实体的反向引用。

子类(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 类型备注
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

不用在映射文件指定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 - 一个字符,'T' 或者'F'

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

表4.4 System.Object 映射类型

NHibernate 类型.NET 类型Database 类型备注
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 映射类型

NHibernate 类型.NET 类型Database 类型备注
StringClob System.String DbType.String type="StringClob" 必须被指定.整个字段被读入内存
BinaryBlob System.Byte[] DbType.Binary type="BinaryBlob" 必须被指定. 整个字段被读入内存
Serializable

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

DbType.Binary type="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>

posted on 2006-07-23 15:04 Minwell 阅读(836) 评论(3)  编辑 收藏 网摘 所属分类: Hibernate

评论

恩楼主说的很详细,希望主楼主进一步交流!   

#2楼  2008-01-11 11:11 zjy [未注册用户]

楼主说的很详细,希望主楼主进一步交流!   回复  引用    

#3楼  2008-04-09 00:33 蓝奇高级验证码识别引擎QQ:631753663 [未注册用户]

出售蓝奇高级验证码识别引擎,可准确识别新浪动网淘宝CSDN等多种复杂验证码。

输出为一个标准DLL,可供VB,VC,Delphi,C#.NET,VB.NET,模拟精灵,按键精灵等多平台调用,调用方法简单,几行代码即可完成。独具特色的边缘检测字符分离、旋转倾斜纠正和通用字符匹配算法(无论字体和大小), 使得该引擎对于像新浪、动网、淘宝、CSDN等多种验证码均有不错的识别率,是一款效果较为理想的验证码识别引擎。附详细的调用实例和代码注释等相关技术文档。

多对一(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: 属性名。

(2)

column (可选):字段名。

(3)

class (可选 - 默认是通过反射得到属性类型): 关联的类的名字。

(4)

cascade (可选): 指明哪些操作会从父对象级联到关联的对象。

(5)

outer-join (可选 - 默认为 auto): 当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。

(6)

update, insert (可选 - 默认为 true)指定对应的字段是否在用于UPDATE 和/或 INSERT的SQL语句中包含。如果二者都是false,则这是一个纯粹的“外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到的,或者通过trigger(除法器),或者是其他程序。

(8)

property-ref: (可选)指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。

(9)

access (可选 - 默认为property): NHibernate 用来访问属性的策略。

(10)

unique (可选):允许产生外键列唯一约束的数据库定义语言(DDL)。

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元素定义的。

<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)

name: 属性的名字

(2)

class (可选 - 默认是通过反射得到的属性类型): 被关联的类的名字.

(3)

cascade (可选) 表明操作是否从父对象级联到被关联的对象。

(4)

contstrainted (可选) 表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。这个选项影响Save()Delete()在级联执行时的先后顺序(也在schema export tool中被使用)。

(5)

outer-join (可选 - 默认为 auto):当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。

(6)

property-ref: (可选): 指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。

(7)

access (可选 - defaults to property): NHibernate 用来访问属性的策略。

有两种不同的一对一关联:

  • 主键关联

  • 惟一外键关联

主键关联不需要额外的表字段;两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!

比如说,对下面的EmployeePerson进行主键一对一关联:

<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实例被赋予和该PersonEmployee属性所指向的Employee实例同样的关键字值。

另一种方式是一个外键和一个惟一关键字对应,上面的EmployeePerson的例子,如果使这种关联方式,应该表达成:

<many-to-one name="Person" class="Person" column="PERSON_ID" unique="true" />

如果在Person的映射加入下面几句,这种关联就是双向的:

<one-to-one name="Employee" class="Employee" property-ref="Person" />

组件(component)

<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)

name: 属性名

(2)

class (可选 - 默认为通过反射得到的属性类型): 组件(子)类的名字。

(3)

insert: 被映射的字段是否出现在SQL的INSERT语句中?

(4)

update: 被映射的字段是否出现在SQL的UPDATE语句中?

(5)

access (可选 - 默认是 property): NHibernate用来访问属性的策略。

property子标签为子类的一些属性和表字段建立映射。

<component>元素允许加入一个 <parent>子元素,在组件类内部就可以有一个指向其容器的实体的反向引用。

 

 

回复   引用     

你可能感兴趣的:(sql,Hibernate,Access,vb,VB.NET)