且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用NHibernate的你也许需要SessionQuicker

更新时间:2022-08-12 22:42:56

    NHibernate功能的强大,勿庸置疑。但是很多地方使用起来也颇为繁琐,比如,无法完整的构建数据层、我们很多时候还是需要绕过NHibernate而直接使用ADO.net;比如,任何一次数据访问,哪怕只是简单的数据读取,我们都需要仔细的处理Session、Transaction。如果你的数据层使用NHibernate构建,那么类似下面的代码可能遍地开花:

            ITransaction trans = null ;
            ISession session 
= null ;
            
try
            {
                session 
= this.factory.OpenSession();
                trans 
= session.BeginTransaction(); 

                
//使用NHibernate的你也许需要SessionQuicker使用NHibernate的你也许需要SessionQuicker访问数据库

                trans.Commit();                
            }
            
catch (Exception ee)
            {                
                
if(trans != null)
                {
                    trans.Rollback();
                }

                
throw ee ;
            }
            
finally
            {
                session.Close() ;
            }

    这种try...catch...finally会在每个需要数据访问的地方重复,这种无聊的Repeat使我忍不住要做点什么。最初,我希望能达到using块的效果,比如像这样:

            using(ISession session = this.factory.OpenSession())
            {
                
//使用NHibernate的你也许需要SessionQuicker使用NHibernate的你也许需要SessionQuicker数据访问
            }

    在using块退出的时候,能自动关闭session和提交/回滚Transaction。如果能这样,那真是太完美了!可是,我真的还不知如何去实现它。(如果你知道,一定请告诉我)
    于是我只好退而求其次,将上面代码中的注释掉的数据访问代码通过delegate抽取出来,这样那个try...catch...finally块就可以重用了。所以我首先定义了两个delegate,一个没有返回值的delegate用于处理“数据命令”,一个有返回值的delegate用于处理“数据查询”。

    public delegate void   CbDoSession(ISession session) ;
    
public delegate object CbDoSessionReturn(ISession session) ;

    在此基础上,SessionQuicker就呼之欲出了:

    public class SessionQuicker
    {
        
private ISessionFactory factory ;    
        
        
#region DataAssemblyName
        
private string dataAssemblyName = "ApplicationServerSystem" ; 
        
public  string DataAssemblyName
        {
            
set
            {
                
this.dataAssemblyName = value ;
            }
        }
        
#endregion        

        
public void Initialize()
        {
            Configuration config 
= new Configuration().AddAssembly(this.dataAssemblyName);
            
this.factory = config.BuildSessionFactory();
        }

        
#region ActionExceptionHandler
        
private IExceptionHandler actionExceptionHandler = null ; 
        
public  IExceptionHandler ActionExceptionHandler
        {
            
set
            {
                
this.actionExceptionHandler = value ;
            }
        }
        
#endregion

        
#region Action
        
public void Action(CbDoSession target ,params object[] args)
        {
            ITransaction trans 
= null ;
            ISession session 
= null ;
            
try
            {
                session 
= this.factory.OpenSession();
                trans 
= session.BeginTransaction(); 
                target(session ,args) ;
                trans.Commit();                
            }
            
catch (Exception ee)
            {                
                
if(trans != null)
                {
                    trans.Rollback();
                }

                
throw ee ;
            }
            
finally
            {
                session.Close() ;
            }
        }
        
#endregion

        
public object ActionReturnObj(CbDoSessionReturn target ,params object[] args)
        {
            ITransaction trans 
= null ;
            ISession session 
= null ;
            
try
            {
                session 
= this.factory.OpenSession();
                trans 
= session.BeginTransaction(); 
                
object res = target(session ,args) ;
                trans.Commit();                

                
return res ;
            }
            
catch (Exception ee)
            {                
                
if(trans != null)
                {
                    trans.Rollback();
                }

                
throw ee ;
            }
            
finally
            {
                session.Close() ;
            }
        }


        
#region safty
        
        
public void ActionSafty(CbDoSession target ,params object[] args)
        {
            
try
            {
                
this.Action(target ,args) ;
            }
            
catch(Exception ee)
            {
                
if(this.actionExceptionHandler != null)
                {
                    
this.actionExceptionHandler.HanleException(ee) ;
                }
            }
        }
        
        
public object ActionReturnObjSafty(CbDoSessionReturn target ,params object[] args)
        {
            
try
            {
                
return this.ActionReturnObj(target ,args) ;
            }
            
catch(Exception ee)
            {
                
if(this.actionExceptionHandler != null)
                {
                    
this.actionExceptionHandler.HanleException(ee) ;
                }

                
return null ;
            }
        }
        
        
#endregion
    }

    
public delegate void   CbDoSession(ISession session ,params object[] args) ;
    
public delegate object CbDoSessionReturn(ISession session ,params object[] args) ;

    在SessionQuicker的帮助下,你可以更简单的进行数据访问,比如:

        private void OnButton1_Click(object sender ,EventArgs args)
        {
            IList list 
= (IList)sessionQuicker.ActionReturnObj(new CbDoSessionReturn(this.ReadStudentList)) ;
            
//使用NHibernate的你也许需要SessionQuicker处理list
        }

        
private object ReadStudentList(ISession ss)
        {    
            IQuery query 
= ss.CreateQuery("from Student as stu where stu.Age > :studentAge" ) ;
            query.SetInt32(
"studentAge" ,20) ;
            
return query.List() ;         
        }

    SessionQuicker的好处是避免了每次数据访问写重复的try...catch...finally块,但是与前面理想的using块比起来,优雅性就要差许多。
    我期待着有人提出更优雅的解决方案!