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>
声明显示的xml命名空间
hibernate-mapping
assembly:程序集名称 , namespace:命名空间名称
还有其它的可选参数
default-lazy:false ,完全禁用延迟加载, 默认是true
class
name:声明持久化类的名称,
table:表的名称
discriminator-value:区分子类
where:在使用此类时,调用 sql where的条件
lazy: 默认是True, 设置为false 可禁用延迟提取
id 主键
name:属性名称
type:nh类型的名称
column:列名称
unsaved-value: 默认值 :sensible , 指定实际是否是新的,未保存的
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
最后面是三个实例,相关类之间的关联。可以看下
看的我热血沸腾啊https://www.ea55.com/
结论部分可提出实际应用建议,提升价值。