前段时间down下来nhibernate的文档,用偶巨烂无比的英文将就着看了一天
觉得还是应该写个demo来体验一把nhibernate带给偶们滴震撼。。。(广告时间)
hoho,就着官方的quickstart和文档,迈出偶勇敢滴第一步![]()
偶们从简单的CRUD开始
先来看基本的查询操作:
/// <summary>
/// get user by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public User Query( string id )
{
Configuration cfg = new Configuration();
cfg.AddAssembly( "NHibernate.Demo" );
//obtain session factory
ISessionFactory factory = cfg.BuildSessionFactory();
//obtain session
ISession session = factory.OpenSession();
//User user = session.Load( typeof( User ), id ) as User;
User user = session.Get( typeof( User ), id ) as User;
session.Close();
return user;
}会话Session中定义的获取EntityClass的方法主要有Get和Load,通过测试后发现两者还是有很大不同的
在文档中的Get(Type clazz, object id)的定义是:
Return the persistent instance of the given entity class with the given identifier, or null if there is no such persistent instance. (If the instance, or a proxy for the instance, is already associated with the session, return that instance or proxy.
而Load( Type theType, object id )的定义是:
Return the persistent instance of the given entity class with the given identifier, assuming that the instance exists.
两者的区别在于:
Get在没有符合查询条件的情况下,将会返回null,若符合,则会返回一个persistent instance;
而Load在没有符合条件的情况下会抛出一个ObejctNotFoundException的异常,若符合,可以返回一个persistent instance或者该持久类的代理类
除此之外呢?google一下,发现在hibernate里有这么种说法(注意是hibernate,没有n)
"get方法仅在内部缓存中查找数据,如没有找到对应数据,将越过二级缓存,直接调用SQL读取数据,而Load方法则充分利用了内部缓存和二级缓存中现有数据"
在nhibernate中没有考证过,看来需要仔细看看nhibernate的cache部分的代码再下结论。。。
再来看插入操作:
/// <summary>
/// insert a record
/// </summary>
/// <returns></returns>
public bool Insert( User newUser )
{
//let NHibernate load all of the mapping files contained in an Assembly:
Configuration cfg = new Configuration();
cfg.AddAssembly( "NHibernate.Demo" );
//obtain session factory
ISessionFactory factory = cfg.BuildSessionFactory();
//obtain session
ISession session = factory.OpenSession();
ITransaction transaction = null;
try
{
//begin transaction
transaction = session.BeginTransaction();
// Tell NHibernate that this object should be saved
session.Save(newUser);
session.Flush(); // force nhibernate accept the change of session right now
// commit all of the changes to the DB and close the ISession
transaction.Commit();
}
catch( HibernateException ex )
{
if( transaction != null )
transaction.Rollback();
throw ex;
}
finally
{
//close session
session.Close();
}
return true;
}代码中session.Flush()并不是必须的,它的作用是将持久类的对象更改立刻提交到数据库中
即使不显式调用session.flush(),在transaction.Commit()之前,nhibernate会自动调用flush()操作
但是请注意,如果在没有使用Transaction的情况下执行持久化操作,
没有调用Flush就关闭session,当前session中的持久对象将不会持久化!(即:所做操作将不能反映到数据源的更改)
事实上,执行持久化操作时,很多情况下,操作是被记录下来,并不是立即提交到数据库,直到session调用Flush时才真正提交。
在SessionImpl.cs中,定义了三个ArrayList,分别是insertions、 deletions、updates,用于保存对应的持久化操作
例如在update()操作之后执行flush(),nhibernate会检查缓存中的持久类,如果发现有更新(在nhibernate中称为IsDirty)
则会提交到数据库,否则将不会提交
原因我想应该是为了避免频繁的数据库连接吧,毕竟数据库连接是非常消耗资源的。
更新和删除操作与增加大体相同,无非是把上面增加操作中的session.Save()操作换做update和delete。代码就不贴了
细心的看官应该能发现一个问题。上述代码中,每个操作开始阶段都做了一编准备Configuration和Session的动作(bad smell)
重复不说,大家看这段代码
//let NHibernate load all of the mapping files contained in an Assembly:
Configuration cfg = new Configuration();
cfg.AddAssembly( "NHibernate.Demo" );
//obtain session factory
ISessionFactory factory = cfg.BuildSessionFactory();
//obtain session
ISession session = factory.OpenSession();得到ISessionFactory的操作是一个类工厂模式,从映射文件中加载相关信息,当映射信息较多时,开销会很大。
看过张老三在博客园期刊里关于nhibernate的文章,收获不少。摘录相关部分代码如下:
private static readonly object lockObj = new object();
private static ISessionFactory _factory;
public static ISessionFactory Factory
{
get
{
if ( _factory == null )
{
lock ( lockObj )
{
if ( _factory == null )
{
Cfg.Configuration cfg = new Cfg.Configuration ();
cfg.AddAssembly( Assembly.GetExecutingAssembly() );
_factory = cfg.BuildSessionFactory();
}
}
}
return _factory;
}
} 
public static ISession GetSession()
{
return Factory.OpenSession();
}这里SessionFactory使用了典型的double lock方式,用来产生线程安全的Singletion(单例)对象。避免了多次实例化的开销
在操作中只需使用GetSession()方法得到会话,即可开始相关操作。
-------------------------
好累,暂时写到这
下次再补


浙公网安备 33010602011771号