schema ="schemaName" (1) default-cascade ="none|save-update" (2) auto-import ="true|false" (3) assembly ="Eg" (4) namespace ="Eg" (5)

各选项说明:

schema (optional): 数据库schema名称。

default-cascade (可选 - 默认为 none): 默认的级联风格。

auto-import (optional - defaults to true ): 指定我们在使用查询语句的时候是否可以使用非全限定名。

(4)(5)

assembly and namespace (可选): 指定映射文件中的类的应用程序集名称和其所在的名称空间名,用来生成类的非全限定名。

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) select-before-update ="true|false" (9) polymorphism ="implicit|explicit" (10) where ="arbitrary sql where condition" (11) persister ="PersisterClass" (12) batch-size ="N" (13) optimistic-lock ="none|version|dirty|all" (14) lazy ="true|false" (15) abstract ="true|false" (16)

各选项说明:

若指明的持久化类实际上是一个接口,这也是完全可以接受的。 之后你可以用元素 <subclass> 来指定该接口的实际实现类。 你可以持久化任何static(静态的)内部类。 你应该使用标准的类名格式来指定类名,比如: Eg.Foo+Bar, Eg 。由于HQL解析器的限制NHibernate 1.0 无法在查询里使用内部类。

不可变类 mutable="false" 不可以被应用程序更新或者删除。 这可以让NHibernate做一些小小的性能优化。

可选的 proxy 属性允许延迟加载类的持久化实例。 NHibernate开始会返回实现了这个命名接口的代理类。当代理的某个方法被实际调用的时候, 真实的持久化对象才会被装载。参见下面的“用于延迟装载的代理”。

Implicit (隐式)的多态是指,如果查询时给出的是任何超类、该类实现的接口或者该类的 名字,都会返回这个类的实例;如果查询中给出的是子类的名字,则会返回子类的实例。 Explicit (显式)的多态是指,只有在查询时给出明确的该类名字时才会返回这个类的实例; 同时只有在这个 <class> 的定义中作为 <subclass> 或者 <joined-subclass> 出现的子类,才会可能返回。 在大多数情况下,默认的 polymorphism="implicit" 都是合适的。 显式的多态在有两个不同的类映射到同一个表的时候很有用。(允许一个“轻型”的类,只包含部分表字段)。

persister 属性可以让你定制这个类使用的持久化策略。 你可以指定你自己实现 NHibernate.Persister.EntityPersister 的子类,你甚至可以完全从头开始编写一个 NHibernate.Persister.IClassPersister 接口的实现, 比如是用储存过程调用、序列化到文件或者LDAP数据库来实现。 参阅 NHibernate.DomainModel.CustomPersister ,这是一个简单的例子 (“持久化” Hashtable )。

请注意 dynamic-update e和 dynamic-insert 的设置并不会继承到子类, 所以在 <subclass> 或者 <joined-subclass> 元素中可能 需要再次设置。这些设置是否能够提高效率要视情形而定。请用你的智慧决定是否使用。

使用 select-before-update 通常会降低性能。如果你重新连接一个脱管(detache)对象实例 到一个Session中时,它可以防止数据库不必要的触发update。 这就很有用了。

如果你打开了 dynamic-update ,你可以选择几种乐观锁定的策略:

  • version (版本检查) 检查version/timestamp字段
  • all (全部) 检查全部字段
  • dirty (脏检查)只检察修改过的字段
  • none (不检查)不使用乐观锁定
  • 我们 非常强烈 建议你在NHibernate中使用version/timestamp字段来进行乐观锁定。 对性能来说,这是最好的选择,并且这也是唯一能够处理在session外进行操作的策略(例如: 在使用 ISession.Update() 的时候)。注意version或者是timestamp属性不能为null,不管是否使用了 unsaved-value 策略,或者是实例被作为是瞬态。

    从NHibernate 1.2.0开始,版本号从1开始(以前的版本从0开始),这样允许把version的属性的 unsaved-value 设置为0。

    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 >

    可选的 <generator> 子元素是一个.NET类的名字, 用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数, 用元素来传递。

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

      所有的生成器都实现NHibernate.Id.IIdentifierGenerator接口。 这是一个非常简单的接口; 某些应用程序可以选择提供他们自己特定的实现。当然, NHibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:

      1、increment

    用于为int类型生成 唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用

      2、identity

    对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。数据库返回的主键值 返回的标识符是int类型的。

      3、sequence

    在DB2,PostgreSQL, Oracle, SAP DB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是int类型的。

      4、hilo

      使用一个高/低位算法来高效的生成int类型的标识符。给定一个表和字段(默认分别是是hibernate_unique_key 和next_hi)作为高位值得来源。 高/低位算法生成的标识符只在一个特定的数据库中是唯一的。在用户自行提供的连接中,不要使用这种生成器。

      5、seqhilo

    使用一个高/低位算法来高效的生成int类型的标识符,给定一个数据库序列(sequence)的名字。

      6、uuid.hex

    用一个System.Guid的ToString()方法法生成字符串类型的标识符, 字符串的长度由format参数定义。

      7、uuid.string

    用一个新的System.Guid实例的byte[]转化为字符串作为标示符。

      8、guid

    使用新的System.Guid实例作为标示符。

      9、guid.comb

    使用Jimmy Nilsson的算法(请参阅http://www.informit.com/articles/article.asp?p=25862)生成一个新的System.Guid标示符。

      10、native

    根据底层数据库的能力选择identity, sequence 或者hilo中的一个。

      11、assigned

    让应用程序在 Save()之前为对象分配一个标示符。

      12、foreign

    使用另外一个相关联的对象的标识符。通常和<one-to-one>联合起来使用。

      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 name="Id" type="Int64" column="cat_id">
            <generator class="seqhilo">
                    <param name="sequence">hi_value</param>
                    <param name="max_lo">100</param>
            </generator>
    

      很不幸,你在为NHibernate自行提供IDbConnection时无法使用hilo。 NHibernate必须能够在一个事务里获取"hi"值。

    <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>
    
      对于内部支持标识字段的数据库(DB2,MySQL,Sybase,MS SQL),你可以使用identity关键字生成。 对于内部支持序列的数据库(DB2,Oracle, PostgreSQL, Interbase, McKoi,SAP DB), 你可以使用sequence风格的关键字生成。 这两种方式对于插入一个新的对象都需要两次SQL查询。
    <id name="Id" type="Int64" column="uid">
            <generator class="sequence">
                    <param name="sequence">uid_sequence</param>
            </generator>
    <id name="Id" type="Int64" column="uid" unsaved-value="0">
            <generator class="identity"/>
    

      对于跨平台开发,native策略会从identity, sequence 和hilo中进行选择,选择哪一个,这取决于底层数据库的支持能力。

      如果你需要应用程序分配一个标示符(而非NHibernate来生成它们),你可以使用assigned生成器。 这种特殊的生成器会使用已经分配给对象的标识符属性的标识符值。用这种特性来分配商业行为的关键字要特别小心(基本上总是一种可怕的设计决定)。

      因为其继承天性,使用这种生成器策略的实体不能通过ISession的SaveOrUpdate()方法保存。作为替代, 你应该明确告知NHibernate是应该被save还是update,分别调用ISession的Save()或Update()方法。

    unsaved-value="any|none" 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>
       在"一棵对象继承树对应一个表"的策略中,<discriminator>元素是必需的, 它定义了表的鉴别器字段。 鉴别器字段包含标志值,用于告知持久化层应该为某个特定的行创建哪一个子类的实例。 如下这些受到限制的类型可以使用: String, Char, Int32, Byte, Short, Boolean , YesNo, TrueFalse
    <discriminator
            column="discriminator_column"        (1)
            type="discriminator_type"            (2)
            force="true|false"                   (3)
            insert="true|false"                  (4)
            formula="arbitrary SQL expression"      (5)
    

      鉴别器字段的实际值是根据discriminator-value<class> and <subclass>元素中 的discriminator-value属性得来的。

      force属性仅仅在这种情况下有用的:表中包含没有被映射到持久化类的附加辨别器值。 这种情况不会经常遇到。

      使用formula属性你可以定义一个SQL表达式,用来判断一个行数据的类型。

    <discriminator formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end" type="Int32"/>

    七、版本(version)(可选)

      <version>元素是可选的,表明表中包含附带版本信息的数据。 这在你准备使用 长事务(long transactions)的时候特别有用。
    <version
            column="version_column"                            (1)
            name="PropertyName"                                (2)
            type="typename"                                    (3)
            access="field|property|nosetter|ClassName"         (4)
            unsaved-value="null|negative|undefined|value"      (5)
            generated="never|always"                           (6)
    
      可选的<timestamp>元素指明了表中包含时间戳数据。 这用来作为版本的替代。 时间戳本质上是一种对乐观锁定的一种不是特别安全的实现。当然, 有时候应用程序可能在其他方面使用时间戳。
    <timestamp
            column="timestamp_column"                 (1)
            name="PropertyName"                        (2)
            access="field|property|nosetter|ClassName"    (3)
            unsaved-value="null|undefined|value"       (4)
            generated="never|always"                  (5)
            insert="true|false"                 (4)
            formula="arbitrary SQL expression"  (5)
            access="field|property|ClassName"   (6)
            optimistic-lock="true|false"        (7)
            generated="never|insert|always"     (8)
    

    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基础类型)指定完整的应用程序集权限定名 (或者是在<hibernate-mapping>里面配置了assemblynamespace属性)。

      NHibernate支持.NET 2.0的可空类型,这些类型和对应的非可空类型处理方式是一致的, 例如:Nullable<Int32>可以对应type="Int32"或者是type="System.Int32"

      如果你没有指定类型,NHibernate会使用反射来得到这个名字的属性, 以此来猜测正确的NHibernate类型。NHibernate会对属性读取器(getter方法)的返回类进行解释, 按照规则2,3,4的顺序。然而,这并不足够。 在某些情况下你仍然需要type属性。 (比如,为了区别NHibernateUtil.DateTimeNHibernateUtil.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)来读取。

    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)

      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"/>

      当然,我们决不鼓励这种用法。

    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)

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

      比如说,对下面的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">Employee</param>
            </generator>
        <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"/>
    insert
    ="true|false" (3) upate="true|false" (4) access="field|property|nosetter|ClassName" (5) optimistic-lock="true|false" (6) <property ...../> <many-to-one .... /> ........ </component>

      其<property>子标签为子类的一些属性与表字段之间建立映射。

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

      <dynamic-component>元素允许把一个 IDictionaryp映射为组件,其属性名对应键值。 参见第 8.5 节 “动态组件 (Dynamic components)”.

    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>
       此外,每个子类可能被映射到他自己的表中(每个子类一个表的策略)。被继承的状态通过和超类的表关联得到。我们使用<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>

      这种映射策略不需要指定辨别标志(discriminator)字段。但是,每一个子类都必须使用 <key>元素指定一个表字段来持有对象的标识符。本章开始的映射可以被用如下方式重写:

    <?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"/>
                    <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">
                    <!-- mapping for Dog could go here -->
            </class>
    </hibernate-mapping>
       第三种选择是仅仅映射类继承树中具体类部分到表中(每个具体类一张表的策略)。 其中,每张表定义了类的所有持久化状态,包括继承的状态。 在 NHibernate 中,并不需要完全显式地映射这样的继承树。 你可以简单地使用单独的<class>定义映射每个类。 然而,如果你想使用多态关联(例如,一个对类继承树中超类的关联),你需要使用<union-subclass>映射。
    <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>

      假设你的应用程序有两个同样名字的持久化类,但是你不想在Hibernate查询中使用他们的全限定名。 除了依赖auto-import="true"以外,类也可以被显式地“import(引用)”。你甚至可以引用没有明确被映射的类和接口。

    <import class="System.Object" rename="Universe"/>
    <import
            class="ClassName"              (1)
            rename="ShortName"             (2)
    
       为了理解很多与持久化服务相关的.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) 属性时的默认值。 System.Byte DbType.Byte 在没有指定类型(type) 属性时的默认值。 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) 属性时的默认值。 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"必须被指定。 System.Globalization.CultureInfo DbType.String - 表明文化(culture)的5个字符 在没有指定类型(type) 属性时的默认值。 Binary System.Byte[] DbType.Binary 在没有指定类型(type) 属性时的默认值。 System.Type DbType.String 保存应用程序集权限定名。 在没有指定类型(type) 属性时的默认值。 String System.String DbType.String 在没有指定类型(type) 属性时的默认值。
       开发者创建属于他们自己的值类型也是很容易的。比如说,你可能希望持久化Int64类型的属性, 持久化成为VARCHAR 字段。NHibernate没有内置这样一种类型。自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。 比如说,你可能有这样的属性: Name { get; set; },这是String类型的,对应的持久化到三个字段:FIRST_NAME, INITIAL, SURNAME

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

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

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

      ICompositeUserType, IEnhancedUserType, INullableUserType, IUserCollectionType, 和 IUserVersionType接口为更特殊的使用方式提供支持。

      你甚至可以在一个映射文件中提供参数给一个IUserType。 为了这样做, 你的UserType必须实现NHibernate.UserTypes.IParameterizedType接口。为了给自定义类型提供参数,你可以在映射文件中使用<type>元素。

    <property name="priority">
        <type name="MyCompany.UserTypes.DefaultValueIntegerType">
            <param name="default">0</param>
        </type>
    </property>

      现在,IUserType 可以从传入的IDictionary对象中得到default 参数的值。

      尽管 NHibernate 内建的丰富的类型和对组件的支持意味着你可能很少 需要使用自定义类型。不过, 为那些在你的应用中经常出现的(非实体)类使用自定义类型也是一个好方法。例如, 一个MonetaryAmount类使用ICompositeUserType来映射是不错的选择,虽然他可以很容易地被映射成组件。这样做的动机之一是抽象。使用自定义类型,以后假若你改变表示金额的方法时,它可以保证映射文件不需要修改。

       这是属性映射的又一种类型。<any> 映射元素定义了一种从多个表到类的多态关联。 这种类型的映射常常需要多于一个字段。第一个字段持有被关联实体的类型,其他的字段持有标识符。 对这种类型的关联来说,不可能指定一个外键约束,所以这当然不是映射(多态)关联的通常的方式。 你只应该在非常特殊的情况下使用它(比如,审计log,用户会话数据等等)。

      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)

      映射文件部分:

    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>
       你可强制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>
       允许在独立的映射文档中定义subclassjoined-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指的是其值由数据库生成的属性。一般来说,如果对象有任何属性由数据库生成值,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_trigger</drop>
        </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">parameterValue</param>
            </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>