Nhibernate是.net环境下的orm工具, 把数据库的实体类对象和数据库中的关系表对象进行一一映射 。

Nhibernate代码生成工具:

各种基于模板的代码生成器(CodeSmith,MyGeneration)

示例解读

<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Eg"
    namespace="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>
  1. 声明显示的xml命名空间

  2. hibernate-mapping

assembly:程序集名称 , namespace:命名空间名称

还有其它的可选参数

default-lazy:false ,完全禁用延迟加载, 默认是true
  1. class

name:声明持久化类的名称,

table:表的名称

discriminator-value:区分子类

where:在使用此类时,调用 sql where的条件

lazy: 默认是True, 设置为false 可禁用延迟提取

  1. id 主键

name:属性名称

type:nh类型的名称

column:列名称

unsaved-value: 默认值 :sensible , 指定实际是否是新的,未保存的

  1. generator:唯一标识符

有参数加param,无参的话,直接 generator =“native”

​ 5.1 increment:整数类型标识符,单进程访问才唯一 ,集群中不要用

​ 5.2 identity:支持DB2, MySQL, MS SQL,Sybase,使用 Convert.ChangeType转化,支持任何整数类型

​ 5.3 sequence, 支持DB2,PostgreSQL,Oracle,Firebird,使用 Convert.ChangeType转化,支持任何整数类型

​ hilo:hi/lo algorit 算法, 列中存在 hibernate_unique_key和 next_hi,

 <generator class="hilo">
                <param name="table">hi_value</param>
                <param name="column">next_value</param>
                <param name="max_lo">100</param>
 </generator>

​ 5.4 seqhilo: hi/lo algorithm算法 生成整数类型标识符。

​ 5.5 uuid.hex 用System.Guid及其ToString(字符串格式)方法生成string类型的标识符
​ 5.6 uuid.string System.Guid创建一个转换为字符串的byte []

​ 5.7 Guid :System.Guid作为标识符
​ 5.8 guid.comb :新的system.Guid算法,参考:http://www.informit.com/articles/article.asp?p=25862.
​ 5.9 native :根据底层数据库来选择, identity, sequence or hilo
​ 5.10 assigned:在save之前,人为的分配
​ 5.11 foreign :使用另一个对旬的标识符,外键

不幸的是,在向NHibernate 提供自己的IDbConnection时 ,不能使用hilo。NHibernate必须能够在新事务中获取“hi”值。

6.复合ID

<composite-id
        name="PropertyName"
        class="ClassName"
        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>

持久化类必须重写Equals() 和GetHashCode()以实现复合标识符相等性。它也必须是Serializable。

discriminator : 特定行实例化哪个子类。

 <discriminator column="subclass" type="Char"/>

column:名称

type:类型

property 属性

<property name="BirthDate" type="Date"/>    

name:类的属性名称

type:nh的类型

column:表的列名,如果不写,则==name

many-to-one

 <many-to-one name="Mate" column="mate_id"/>
<many-to-one
        name="PropertyName"                                (1)
        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)
/>

name:类的属性名称

column:表的列名,如果不写,则==name

class:关联类的名称

cascade:哪些从父对象到关联对象

cascade =“all | none | save-update | delete” 

one-to-one

<one-to-one
        name="PropertyName"                                (1)
        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)
/>

name:类的属性名称

class:关联类的名称

排序

nh支持实现这两个接口System.Collections.SortedList and Iesi.Collections.SortedSet.的集合

<set name="Aliases" table="person_aliases" order-by="name asc">
    <key column="person"/>
    <element column="name" type="String"/>
</set>

注意:order-by后面的是列名

刷新会话

ISession.Flush()与数据库同步。

事物

tx.Commit(); //刷新会话并提交事务
tx.Rollback(); //回滚事务

Interceptors拦截器

在保存和操作对象之前进行操作。

using System;
using NHibernate.Type;

namespace NHibernate.Test
{
    [Serializable]
    public class AuditInterceptor : IInterceptor
    {
    
        private int updates;
        private int creates;
    
        public void OnDelete(object entity,
                             object id,
                             object[] state,
                             string[] propertyNames,
                             IType[] types)
        {
            // do nothing
        }
    
        public boolean OnFlushDirty(object entity, 
                                    object id, 
                                    object[] currentState,
                                    object[] previousState,
                                    string[] propertyNames,
                                    IType[] types) {
    
            if ( entity is IAuditable )
            {
                updates++;
                for ( int i=0; i < propertyNames.Length; i++ )
                {
                    if ( "LastUpdateTimestamp" == propertyNames[i] )
                    {
                        currentState[i] = DateTime.Now;
                        return true;
                    }
                }
            }
            return false;
        }
    
        public boolean OnLoad(object entity, 
                              object id,
                              object[] state,
                              string[] propertyNames,
                              IType[] types)
        {
            return false;
        }
    
        public boolean OnSave(object entity,
                              object id,
                              object[] state,
                              string[] propertyNames,
                              IType[] types)
        {
            if ( entity is IAuditable )
            {
                creates++;
                for ( int i=0; i<propertyNames.Length; i++ )
                {
                    if ( "CreateTimestamp" == propertyNames[i] )
                    {
                        state[i] = DateTime.Now;
                        return true;
                    }
                }
            }
            return false;
        }
    
        public void PostFlush(ICollection entities)
        {
            Console.Out.WriteLine("Creations: {0}, Updates: {1}", creates, updates);
        }
    
        public void PreFlush(ICollection entities) {
            updates=0;
            creates=0;
        }
        
    }
}

创建会话时,指定拦截器

ISession session = sf.OpenSession(new AuditInterceptor());

在全局配置中设置拦截器

new Configuration().SetInterceptor(new AuditInterceptor());

批量插入的问题

插入10万行数据,用如下的代码会出现OutOfMemoryException 在5000行的时候。这 是因为nh将新插入的实例缓存在会话级缓存中。

ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
for(int i = 0; i <100000; i ++){
    客户客户=新客户(.....);
    session.Save(客户);
}
tx.Commit();
session.Close();

方案1. 控制缓存区大小

所以要在有大量数据操作时,定期 的flush 然后clear来控制第一级缓存的大小

ISession session = sessionFactory.openSession();
ITransaction tx = session.BeginTransaction();
   
for(int i = 0; i <100000; i ++){
    客户客户=新客户(.....);
    session.Save(客户);
    if(i%20 == 0){// 20,与ADO批量大小相同
        //刷新一批插入并释放内存:
        调用Session.flush();
        session.Clear();
    }
}
   
tx.Commit();
session.Close();

方案2 用StatelessSession接口

对象不持久会,会马上执行insert, update,delete和直接写Sql语句一样,

IStatelessSession session = sessionFactory.OpenStatelessSession();
ITransaction tx = session.BeginTransaction();
   
var customers = session.GetNamedQuery(“GetCustomers”)
    .Enumerable <顾客>();
while(customers.MoveNext()){
    客户客户=客户。当前;
    customer.updateStuff(...);
    了Session.update(客户);
}
   
tx.Commit();
session.Close();

方案3,dml操作

IQuery.ExecuteUpdate()返回 的int值 方法表示操作影响的实体数

ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();

string hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
// or string hqlUpdate = "update Customer set name = :newName where name = :oldName";
int updatedEntities = s.CreateQuery( hqlUpdate )
        .SetString( "newName", newName )
        .SetString( "oldName", oldName )
        .ExecuteUpdate();
tx.Commit();
session.Close();

INSERT语句 的伪语法是: INSERT INTO EntityName properties_list select_statement

不支持insert into ... values ...

ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();

var hqlInsert =“insert into DelinquentAccount(id,name)select c.id,c.name from Customer c where ...”;
int createdEntities = s.CreateQuery(hqlInsert)
        .ExecuteUpdate();
tx.Commit();
session.Close();

参考:https://nhibernate.info/previous-doc/v3.3/single/index.html#quickstart

最后面是三个实例,相关类之间的关联。可以看下


本文由 hcb 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论