NHibernate文档翻译 第4章 O/R Mapping基础
2005-11-14 16:13
573 查看
第 4 章 O/R Mapping基础
目录
映射声明(Mapping declaration)
Schema
hibernate-mapping
class
id
联合ID(composite-id)
识别器(discriminator)
版本(version)(可选)
时间戳(timestamp )(可选)
property
多对一(many-to-one)
一对一(one-to-one)
组件(component)
子类(subclass)
连接的子类(joined-subclass)
map, set, list, bag
引用(import)
NHibernate的类型
实体(Entities)和值(values)
基本值类型
自定义值类型
映射到"任意"(any)类型
SQL中引号包围的标识符
映射文件的模块化(Modular mapping files)
映射声明(Mapping declaration)
对象和关系数据库之间的映射是用一个XML文档(XML document)来定义的。这个映射文档被设计为易读的,并且可以手工修改。映射语言是以.NET为中心的,意味着映射是按照持久化类的定义来创建的,而非表的定义。
请注意,虽然很多Hibernate用户选择手工定义XML映射文档,也有一些工具来生成映射文档,包括XDoclet,Middlegen和AndroMDA.
译者注:这里是NHibernate文档中一处没有从Hibernate文档中转换过来的部分,NHibernate中并没有像XDoclet,Middlegen和AndroMDA这样的工具,我一般会采用MyGeneration这样的代码生成工具来生成XML配置文档。
让我们从一个映射的例子开始:
我们现在开始讨论映射文档的内容。我们只描述NHibernate在运行时用到的文档元素和属性。映射文档还包括一些额外的可选属性和元素,它们在使用schema导出工具的时候会影响导出的数据库schema结果。(比如,
Schema
所有的XML映射都需要使用nhibernate-mapping-2.0 schema。目前的schema可以在NHibernate的资源路径或者是
在使用VisualStudio.NET时,你应该将
hibernate-mapping
这个元素包括四个可选的属性。
假若你有两个持久化类,它们的非全限定名是一样的(就是在不同的命名空间里面--译者注),你应该设置
class
你可以使用
若指明的持久化类实际上是一个接口,也可以被完美地接受。其后你可以用
不可变类,
可选的proxy属性可以允许延迟加载类的持久化实例。NHibernate开始会返回实现了这个命名接口或者子类(通过的Castle.DynamicProxy)。当代理的某个方法被实际调用的时候,真实的持久化对象才会被装载。参见下面的“用于延迟装载的代理”。
Implicit (隐式)的多态是指,如果查询中给出的是任何超类、该类实现的接口或者该类的名字,都会返回这个类的实例;如果查询中给出的是子类的名字,则会返回子类的实例。Explicit (显式)的多态是指,只有在查询中给出的明确是该类的名字时才会返回这个类的实例;同时只有当在这个
persister属性可以让你定制这个类使用的持久化策略。你可以指定你自己实现的
请注意
id
被映射的类必须声明对应数据库表主键字段。大多数类有一个属性,为每一个实例包含唯一的标识。
如果
还有一个另外的
generator
必须声明的
所有的生成器都实现
对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。返回的标识符是
对DB2,MySQL, PostgreSQL, Oracle的内置标识字段提供支持。返回的标识符是
使用一个高/低位算法来高效的生成
使用一个高/低位算法来高效的生成
用一个
用一个新的
用一个新的
用Jimmy Nilsson在文章http://www.informit.com/articles/article.asp?p=25862中描述的算法产生一个新的
根据底层数据库的能力选择
让应用程序在
使用另外一个相关联的对象的标识符。和
高/低位算法(Hi/Lo Algorithm)
很不幸,你在为NHibernate自行提供Connection的时候无法使用
UUID Hex 算法
UUID是通过调用
UUID String 算法
UUID是通过调用
GUID 算法
标识字段和序列(Identity columns and Sequences)
对于内部支持标识字段的数据库(DB2,MySQL,Sybase,MS SQL),你可以使用
对于跨平台开发,
程序分配的标识符(Assigned Identifiers)
如果你需要应用程序分配一个标示符(而非NHibernate来生成它们),你可以使用
因为其继承天性,使用这种生成器策略的实体不能通过ISession的
联合ID(composite-id)
如果表使用联合主键,你可以把类的多个属性组合成为标识符属性。
你的持久化类必须重载
不幸的是,这种组合关键字的方法意味着一个持久化类是它自己的标识。除了对象自己之外,没有什么方便的“把手”可用。你必须自己初始化持久化类的实例,在使用组合关键字
识别器(discriminator)
在"一棵对象继承树对应一个表"的策略中,
标识器字段的实际值是根据
目录
映射声明(Mapping declaration)
Schema
hibernate-mapping
class
id
联合ID(composite-id)
识别器(discriminator)
版本(version)(可选)
时间戳(timestamp )(可选)
property
多对一(many-to-one)
一对一(one-to-one)
组件(component)
子类(subclass)
连接的子类(joined-subclass)
map, set, list, bag
引用(import)
NHibernate的类型
实体(Entities)和值(values)
基本值类型
自定义值类型
映射到"任意"(any)类型
SQL中引号包围的标识符
映射文件的模块化(Modular mapping files)
映射声明(Mapping declaration)
对象和关系数据库之间的映射是用一个XML文档(XML document)来定义的。这个映射文档被设计为易读的,并且可以手工修改。映射语言是以.NET为中心的,意味着映射是按照持久化类的定义来创建的,而非表的定义。
请注意,虽然很多Hibernate用户选择手工定义XML映射文档,也有一些工具来生成映射文档,包括XDoclet,Middlegen和AndroMDA.
译者注:这里是NHibernate文档中一处没有从Hibernate文档中转换过来的部分,NHibernate中并没有像XDoclet,Middlegen和AndroMDA这样的工具,我一般会采用MyGeneration这样的代码生成工具来生成XML配置文档。
让我们从一个映射的例子开始:
<?xml version="1.0" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" namespace="Eg" assembly="Eg"> <class name="Cat" table="CATS" discriminator-value="C"> <id name="Id" column="uid" type="Int64"> <generator class="hilo"/> </id> <discriminator column="subclass" type="Char"/> <property name="Birthdate" type="Date"/> <property name="Color" not-null="true"/> <property name="Sex" not-null="true" update="false"/> <property name="Weight"/> <many-to-one name="Mate" column="mate_id"/> <set name="Kittens"> <key column="mother_id"/> <one-to-many class="Cat"/> </set> <subclass name="DomesticCat" discriminator-value="D"> <property name="Name" type="String"/> </subclass> </class> <class name="Dog"> <!-- mapping for Dog could go here --> </class> </hibernate-mapping>
我们现在开始讨论映射文档的内容。我们只描述NHibernate在运行时用到的文档元素和属性。映射文档还包括一些额外的可选属性和元素,它们在使用schema导出工具的时候会影响导出的数据库schema结果。(比如,
not-null属性。)
Schema
所有的XML映射都需要使用nhibernate-mapping-2.0 schema。目前的schema可以在NHibernate的资源路径或者是
NHibernate.dll的嵌入资源(Embedded Resource)中找到。NHibernate总是会优先使用嵌入在资源中的schema文件。
在使用VisualStudio.NET时,你应该将
hibernate-mapping拷贝到
C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Packages\schemas\xml路径中,以获得智能感知功能。
hibernate-mapping
这个元素包括四个可选的属性。
schema属性,指明了这个映射所引用的表所在的schema名称。假若指定了这个属性,表名会加上所指定的schema的名字扩展为全限定名。假若没有指定,表名就不会使用全限定名。
default-cascade指定了未明确注明cascade属性的属性和集合类会采取什么样的默认级联风格。auto-import属性默认让我们在查询语言中可以使用非全限定名的类名。
default-access告诉我们怎么访问属性值。
<hibernate-mapping schema="schemaName" (1) default-cascade="none|save-update" (2) auto-import="true|false" (3) default-access="property|field|nosetter|ClassName" (4) assembly="assembly.name" (5) namespace="namespace.name" (6) >
(1) | schema(可选): 数据库schema名称. |
(2) | default-cascade(可选 - 默认为 none): 默认的级联风格. |
(3) | auto-import(可选 - 默认为 true): 指定是否我们可以在查询语言中使用非全限定的类名(仅限于本映射文件中的类)。 |
(4) | default-access(可选 - 默认为 property): NHibernate访问属性值时的策略。 |
(5) | assembly(可选): 指定一个程序集,如果在映射文档中没有指定程序集,就使用这个程序集。 |
(6) | namespace(可选): 指定一个命名空间前缀,如果在映射文档中没有指定全限定名,就使用这个命名空间名。 |
auto-import="false"。假若说你把一个“import过”的名字同时对应两个类, NHibernate会抛出一个异常。
class
你可以使用
class元素来定义一个持久化类:
<class name="ClassName" (1) table="tableName"(2) discriminator-value="discriminator_value"(3) mutable="true|false"(4) schema="owner"(5) proxy="ProxyInterface"(6) dynamic-update="true|false"(7) dynamic-insert="true|false"(8) polymorphism="implicit|explicit"(9) where="arbitrary sql where condition"(10) persister="PersisterClass"(11) lazy="true|false"(12) />
(1) | name: 持久化类(或者接口)的全限定名。 |
(2) | table: 对应的数据库表名。 |
(3) | discriminator-value(可选 - 默认和类名一样): 一个用于区分不同的子类的值,在多态行为时使用。 |
(4) | mutable(可选, 默认为 true): 表明该类的实例可变(不可变)。 |
(5) | schema(可选): 覆盖在根 <hibernate-mapping>元素中指定的schema名字。 |
(6) | proxy(可选): 指定一个接口,在延迟装载时作为代理使用。你可以在这里使用该类自己的名字。 |
(7) | dynamic-update(可选, 默认为 false): 指定用于 UPDATE的SQL将会在运行时动态生成,并且只更新那些改变过的字段。 |
(8) | dynamic-insert(可选, 默认为 false): 指定用于 INSERT的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。 |
(9) | polymorphism(可选, 默认为 implicit(隐式)): 界定是隐式还是显式的使用查询多态。 |
(10) | where(可选) 指定一个附加的SQL WHERE条件,在抓取这个类的对象时会一直增加这个条件。 |
(11) | persister(可选): 指定一个定制的 IClassPersister. |
(12) | lazy(可选):假若设置 lazy="true",就是设置这个类自己的名字作为proxy接口的一种等价快捷形式。 |
<subclass>来指定该接口的实际实现类名。你可以持久化任何static(静态的)内部类。记得应该使用标准的类名格式,就是说比如:
Eg.Foo+Bar
不可变类,
mutable="false"不可以被应用程序更新或者删除。这可以让NHibernate做一些小小的性能优化。
可选的proxy属性可以允许延迟加载类的持久化实例。NHibernate开始会返回实现了这个命名接口或者子类(通过的Castle.DynamicProxy)。当代理的某个方法被实际调用的时候,真实的持久化对象才会被装载。参见下面的“用于延迟装载的代理”。
Implicit (隐式)的多态是指,如果查询中给出的是任何超类、该类实现的接口或者该类的名字,都会返回这个类的实例;如果查询中给出的是子类的名字,则会返回子类的实例。Explicit (显式)的多态是指,只有在查询中给出的明确是该类的名字时才会返回这个类的实例;同时只有当在这个
<class>的定义中作为
<subclass>或者
<joined-subclass>出现的子类,才会可能返回。 大多数情况下,默认的
polymorphism="implicit"都是合适的。 显式的多态在有两个不同的类映射到同一个表的时候很有用。(允许一个“轻型”的类,只包含部分表字段)。
persister属性可以让你定制这个类使用的持久化策略。你可以指定你自己实现的
NHibernate.Persister.EntityPersister的子类,你甚至可以完全从头开始编写一个
NHibernate.Persister.IClassPersister接口的实现,可能是用储存过程调用、序列化到文件或者LDAP数据库来实现的。参阅
NHibernate.DomainModel.CustomPersister,这是一个简单的例子(“持久化”到一个Hashtable)。
请注意
dynamic-update和
dynamic-insert的设置并不会继承到子类,所以在
<subclass>或者
<joined-subclass>元素中可能需要再次设置。这些设置是否能够提高效率要视情形而定。请用你的智慧决定是否使用。
id
被映射的类必须声明对应数据库表主键字段。大多数类有一个属性,为每一个实例包含唯一的标识。
<id>元素定义了该属性到数据库表主键字段的映射。
<id name="propertyName" (1) type="typename" (2) column="column_name" (3) unsaved-value="any|none|null|id_value" (4) access="field|property|nosetter|ClassName"> (5) <generator class="generatorClass"/> </id>
(1) | name(可选): 标识属性的名字。 |
(2) | type(可选): 标识NHibernate类型的名字。 |
(3) | column(可选 - 默认为属性名): 主键字段的名字。 |
(4) | unsaved-value(可选 - 默认为 null): 一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。这可以把这种实例和从以前的session中装载过(可能又做过修改--译者注)但未再次持久化的实例区分开来。 |
(5) | access(可选 - 默认为 property): NHibernate用来访问属性值的策略。 |
name属性不存在,会认为这个类没有标识属性。
unsaved-value属性很重要!如果你的类的标识属性不是默认为
null的,你应该指定正确的默认值。特别重要的是在使用值类型
System.ValueType例如
System.Int32或者
System.Guid作为你的
<id>属性时确保清楚的设置这个属性,因为
System.ValueType对象不可能为
null值。
还有一个另外的
<composite-id>声明可以访问旧式的多主键数据。我们强烈不鼓励使用这种方式。
generator
必须声明的
<generator>子元素是一个.NET类的名字,用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数,用
<param>元素来传递。
<id name="Id" type="Int64" column="uid" unsaved-value="0"> <generator class="NHibernate.Id.TableHiLoGenerator"> <param name="table">uid_table</param> <param name="column">next_hi_value_column</param> </generator> </id>
所有的生成器都实现
NHibernate.Id.IdentifierGenerator接口。这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然,NHibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:
identity
对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。返回的标识符是
Int64,
Int32或者
Int16类型的。
sequence(序列)
对DB2,MySQL, PostgreSQL, Oracle的内置标识字段提供支持。返回的标识符是
Int64
Int32或者
Int16类型的。
hilo(高低位)
使用一个高/低位算法来高效的生成
Int64,
Int32或者
Int16类型的标识符。给定一个表和字段(默认分别是
hibernate_unique_key和
next)作为高位值得来源。高/低位算法生成的标识符只在一个特定的数据库中是唯一的。
seqhilo(使用序列的高低位)
使用一个高/低位算法来高效的生成
Int64,
Int32或者
Int16类型的标识符,给定一个数据库序列(sequence)的名字。
uuid.hex
用一个
System.Guid和它的
ToString(string format)方法生成字符串类型的标识符。字符串的长度取决于
format的配置。
uuid.string
用一个新的
System.Guid产生一个
byte[],把它转换成字符串。
guid
用一个新的
System.Guid作为标识符。
guid.comb
用Jimmy Nilsson在文章http://www.informit.com/articles/article.asp?p=25862中描述的算法产生一个新的
System.Guid。
native(本地)
根据底层数据库的能力选择
identity,
sequence或者
hilo中的一个。
assigned(程序设置)
让应用程序在
save()之前为对象分配一个标示符。
foreign(外部引用)
使用另外一个相关联的对象的标识符。和
<one-to-one>联合一起使用。
高/低位算法(Hi/Lo Algorithm)
hilo和
seqhilo生成器给出了两种hi/lo算法的实现,这是一种很令人满意的标识符生成算法。第一种实现需要一个“特殊”的数据库表来保存下一个可用的“hi”值。第二种实现使用一个Oracle风格的序列(在被支持的情况下)。
<id name="Id" type="Int64" column="cat_id"> <generator class="hilo"> <param name="table">hi_value</param> <param name="column">next_value</param> <param name="max_lo">100</param> </generator> </id>
<id name="Id" type="Int64" column="cat_id"> <generator class="seqhilo"> <param name="sequence">hi_value</param> <param name="max_lo">100</param> </generator> </id>
很不幸,你在为NHibernate自行提供Connection的时候无法使用
hilo。Hibernate必须能够在一个新的事务中得到一个"hi"值。
UUID Hex 算法
<id name="Id" type="String" column="cat_id"> <generator class="uuid.hex"> <param name="format">format_value</param> <param name="seperator">seperator_value</param> </generator> </id>
UUID是通过调用
Guid.NewGuid().ToString(format)产生的。format值的设置请参考MSDN文档。默认的
seperator很少也不应该被改变。
format决定是否配置好的
seperator能替换默认的seperator,并提供给自己使用(译者注:此句可能和原文有出入,请参见英文文档)。
UUID String 算法
UUID是通过调用
Guid.NewGuid().ToByteArray()并且把
byte[]转换成
char[],
char[]做为一个16个字符组成的字符串返回。
GUID 算法
guid标识符通过调用
Guid.NewGuid()产生。 为了提升Guids在MS SQL中作为主键,外键和索引的一部分时的性能,可以使用
guid.comb。在别的数据库中使用
guid.comb的好处是支持非标准的GUID。
标识字段和序列(Identity columns and Sequences)
对于内部支持标识字段的数据库(DB2,MySQL,Sybase,MS SQL),你可以使用
identity关键字生成。对于内部支持序列的数据库(DB2,Oracle, PostgreSQL),你可以使用
sequence风格的关键字生成。这两种方式对于插入一个新的对象都需要两次SQL查询。当使用MS SQL并且采用
identity主键生成器,
select SCOPE_IDENTITY()将会被附加到
insert的sql语句,因而不可避免的执行两个不同的
IDbCommand。
<id name="Id" type="Int64" column="uid"> <generator class="sequence"> <param name="sequence">uid_sequence</param> </generator> </id>
<id name="Id" type="Int64" column="uid" unsaved-value="0"> <generator class="identity"/> </id>
对于跨平台开发,
native策略会从identity, sequence 和hilo中进行选择,取决于底层数据库的支持能力。
程序分配的标识符(Assigned Identifiers)
如果你需要应用程序分配一个标示符(而非NHibernate来生成它们),你可以使用
assigned生成器。这种特殊的生成器会使用已经分配给对象的标识符属性的标识符值。用这种特性来分配商业行为的关键字要特别小心(基本上总是一种可怕的设计决定)。
因为其继承天性,使用这种生成器策略的实体不能通过ISession的
SaveOrUpdate()方法保存。作为替代,你应该明确告知NHibernate是应该被save还是update,分别调用ISession的
Save()或
Update()方法。
联合ID(composite-id)
<composite-id name="propertyName"(1) class="ClassName"(2) unsaved-value="any|none"(3) access="field|property|nosetter|ClassName"> <key-property name="propertyName" type="typename" column="column_name"/> <key-many-to-one name="propertyName class="ClassName" column="column_name"/> ...... </composite-id>
如果表使用联合主键,你可以把类的多个属性组合成为标识符属性。
<composite-id>元素接受
<key-property>属性映射和
<key-many-to-one>属性映射作为子元素。
<composite-id> <key-property name="medicareNumber"/> <key-property name="dependent"/> </composite-id>
你的持久化类必须重载
Equals()和
HashCode()方法,来实现组合的标识符判断等价.也必须实现
Serializable接口
不幸的是,这种组合关键字的方法意味着一个持久化类是它自己的标识。除了对象自己之外,没有什么方便的“把手”可用。你必须自己初始化持久化类的实例,在使用组合关键字
Load()持久化状态之前,必须填充他的联合属性。我们会在TODO:LINKTOCOMPENENTS中说明一种更加方便的方法,把联合标识实现为一个独立的类,下面描述的属性只对这种备用方法有效:
(1) | name(可选): 一个组件类型,持有联合标识(参见下一节)。 |
(2) | class(可选 - 默认为通过反射(reflection)得到的属性类型): 作为联合标识的组件类名(参见下一节)。 |
(3) | unsaved-value(可选 - 默认为 none): 假如被设置为 any的值,就表示新创建,尚未被持久化的实例将持有的值。 |
在"一棵对象继承树对应一个表"的策略中,
<discriminator>元素是必需的,它声明了表的识别器字段。识别器字段包含标志值,用于告知持久化层应该为某个特定的行创建哪一个子类的实例。只能使用如下受到限制的一些类型:
String,
Char,
Int32,
Byte,
Int16,
Boolean,
YesNo,
TrueFalse.
<discriminator column="discriminator_column"(1) type="discriminator_type"(2) force="true|false"(3) insert="true|false" (4) />
(1) | column(可选 - 默认为 class) 识别器字段的名字 |
(2) | type(可选 - 默认为 String) 一个NHibernate字段类型的名字 |
(3) | force(可选 - 默认为 false) "强制"NHibernate指定允许的识别器值,就算取得的所有实例都是根类的。 |
(4) | insert(可选 - 默认为 true) 当识别器是被映射的组件的标识符的一部分时设置为 false。 |
<class>和
<subclass>元素的
discriminator-value得来%
相关文章推荐
- NHibernate文档翻译 第4章----O/R Mapping基础
- NHibernate文档翻译---O/R Mapping基础
- NHibernate文档翻译---使用AttributesNHibernate.Mapping.Attributes
- NHibernate文档翻译 第9章----使用AttributesNHibernate.Mapping.Attributes
- NHibernate文档翻译 第9章 使用AttributesNHibernate.Mapping.Attributes
- NHibernate官方文档中文版--基础ORM(Basic O/R Mapping)
- NHibernate翻译文档提供下载(chm和html格式)
- NHibernate中文翻译文档
- NHibernate文档翻译-- ISessionFactory配置
- Mako 模板系统文档翻译(1) 使用基础
- ABP官方文档翻译 9.3 NHibernate集成
- NHibernate文档翻译 第8章----NHibernate缓存(NHibernate.Caches)
- 8月目标翻译Elasticsearch的mapping文档
- CNTK API文档翻译(21)——深度卷积GAN处理MSIST数据基础
- 微软免费图书《Introducing Microsoft LINQ》翻译-第4章:LINQ句法基础 查询语法
- AGG 文档翻译 - 基础渲染器
- NHibernate文档翻译 第3章 持久化类(Persistent Classes)
- NHibernate文档翻译 第6章 关联映射
- NHibernate文档翻译 第8章 NHibernate缓存(NHibernate.Caches)
- NHibernate中文翻译文档(整理自DDLLY命名空间)