导航

Nhibernate之初体验(一)

Posted on 2006-01-11 18:40  ivanking  阅读(1308)  评论(5)    收藏  举报

前段时间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()方法得到会话,即可开始相关操作。

-------------------------
好累,暂时写到这
下次再补