NHibernate功能的强大,勿庸置疑。但是很多地方使用起来也颇为繁琐,比如,无法完整的构建数据层、我们很多时候还是需要绕过NHibernate而直接使用ADO.net;比如,任何一次数据访问,哪怕只是简单的数据读取,我们都需要仔细的处理Session、Transaction。如果你的数据层使用NHibernate构建,那么类似下面的代码可能遍地开花:
ITransactiontrans
=
null
;
ISessionsession = null ;
try
{
session = this .factory.OpenSession();
trans = session.BeginTransaction();
// 访问数据库
trans.Commit();
}
catch (Exceptionee)
{
if (trans != null )
{
trans.Rollback();
}
throw ee;
}
finally
{
session.Close();
}
ISessionsession = null ;
try
{
session = this .factory.OpenSession();
trans = session.BeginTransaction();
// 访问数据库
trans.Commit();
}
catch (Exceptionee)
{
if (trans != null )
{
trans.Rollback();
}
throw ee;
}
finally
{
session.Close();
}
这种try...catch...finally会在每个需要数据访问的地方重复,这种无聊的Repeat使我忍不住要做点什么。最初,我希望能达到using块的效果,比如像这样:
using
(ISessionsession
=
this
.factory.OpenSession())
{
// 数据访问
}
{
// 数据访问
}
在using块退出的时候,能自动关闭session和提交/回滚Transaction。如果能这样,那真是太完美了!可是,我真的还不知如何去实现它。(如果你知道,一定请告诉我)
于是我只好退而求其次,将上面代码中的注释掉的数据访问代码通过delegate抽取出来,这样那个try...catch...finally块就可以重用了。所以我首先定义了两个delegate,一个没有返回值的delegate用于处理“数据命令”,一个有返回值的delegate用于处理“数据查询”。
public
delegate
void
CbDoSession(ISessionsession);
public delegate object CbDoSessionReturn(ISessionsession);
public delegate object CbDoSessionReturn(ISessionsession);
在此基础上,SessionQuicker就呼之欲出了:
public
class
SessionQuicker
{
private ISessionFactoryfactory;
#region DataAssemblyName
private string dataAssemblyName = " ApplicationServerSystem " ;
public string DataAssemblyName
{
set
{
this .dataAssemblyName = value;
}
}
#endregion
public void Initialize()
{
Configurationconfig = new Configuration().AddAssembly( this .dataAssemblyName);
this .factory = config.BuildSessionFactory();
}
#region ActionExceptionHandler
private IExceptionHandleractionExceptionHandler = null ;
public IExceptionHandlerActionExceptionHandler
{
set
{
this .actionExceptionHandler = value;
}
}
#endregion
#region Action
public void Action(CbDoSessiontarget, params object []args)
{
ITransactiontrans = null ;
ISessionsession = null ;
try
{
session = this .factory.OpenSession();
trans = session.BeginTransaction();
target(session,args);
trans.Commit();
}
catch (Exceptionee)
{
if (trans != null )
{
trans.Rollback();
}
throw ee;
}
finally
{
session.Close();
}
}
#endregion
public object ActionReturnObj(CbDoSessionReturntarget, params object []args)
{
ITransactiontrans = null ;
ISessionsession = null ;
try
{
session = this .factory.OpenSession();
trans = session.BeginTransaction();
object res = target(session,args);
trans.Commit();
return res;
}
catch (Exceptionee)
{
if (trans != null )
{
trans.Rollback();
}
throw ee;
}
finally
{
session.Close();
}
}
#region safty
public void ActionSafty(CbDoSessiontarget, params object []args)
{
try
{
this .Action(target,args);
}
catch (Exceptionee)
{
if ( this .actionExceptionHandler != null )
{
this .actionExceptionHandler.HanleException(ee);
}
}
}
public object ActionReturnObjSafty(CbDoSessionReturntarget, params object []args)
{
try
{
return this .ActionReturnObj(target,args);
}
catch (Exceptionee)
{
if ( this .actionExceptionHandler != null )
{
this .actionExceptionHandler.HanleException(ee);
}
return null ;
}
}
#endregion
}
public delegate void CbDoSession(ISessionsession, params object []args);
public delegate object CbDoSessionReturn(ISessionsession, params object []args);
{
private ISessionFactoryfactory;
#region DataAssemblyName
private string dataAssemblyName = " ApplicationServerSystem " ;
public string DataAssemblyName
{
set
{
this .dataAssemblyName = value;
}
}
#endregion
public void Initialize()
{
Configurationconfig = new Configuration().AddAssembly( this .dataAssemblyName);
this .factory = config.BuildSessionFactory();
}
#region ActionExceptionHandler
private IExceptionHandleractionExceptionHandler = null ;
public IExceptionHandlerActionExceptionHandler
{
set
{
this .actionExceptionHandler = value;
}
}
#endregion
#region Action
public void Action(CbDoSessiontarget, params object []args)
{
ITransactiontrans = null ;
ISessionsession = null ;
try
{
session = this .factory.OpenSession();
trans = session.BeginTransaction();
target(session,args);
trans.Commit();
}
catch (Exceptionee)
{
if (trans != null )
{
trans.Rollback();
}
throw ee;
}
finally
{
session.Close();
}
}
#endregion
public object ActionReturnObj(CbDoSessionReturntarget, params object []args)
{
ITransactiontrans = null ;
ISessionsession = null ;
try
{
session = this .factory.OpenSession();
trans = session.BeginTransaction();
object res = target(session,args);
trans.Commit();
return res;
}
catch (Exceptionee)
{
if (trans != null )
{
trans.Rollback();
}
throw ee;
}
finally
{
session.Close();
}
}
#region safty
public void ActionSafty(CbDoSessiontarget, params object []args)
{
try
{
this .Action(target,args);
}
catch (Exceptionee)
{
if ( this .actionExceptionHandler != null )
{
this .actionExceptionHandler.HanleException(ee);
}
}
}
public object ActionReturnObjSafty(CbDoSessionReturntarget, params object []args)
{
try
{
return this .ActionReturnObj(target,args);
}
catch (Exceptionee)
{
if ( this .actionExceptionHandler != null )
{
this .actionExceptionHandler.HanleException(ee);
}
return null ;
}
}
#endregion
}
public delegate void CbDoSession(ISessionsession, params object []args);
public delegate object CbDoSessionReturn(ISessionsession, params object []args);
在SessionQuicker的帮助下,你可以更简单的进行数据访问,比如:
private
void
OnButton1_Click(
object
sender,EventArgsargs)
{
IListlist = (IList)sessionQuicker.ActionReturnObj( new CbDoSessionReturn( this .ReadStudentList));
// 处理list
}
private object ReadStudentList(ISessionss)
{
IQueryquery = ss.CreateQuery( " fromStudentasstuwherestu.Age>:studentAge " );
query.SetInt32( " studentAge " , 20 );
return query.List();
}
{
IListlist = (IList)sessionQuicker.ActionReturnObj( new CbDoSessionReturn( this .ReadStudentList));
// 处理list
}
private object ReadStudentList(ISessionss)
{
IQueryquery = ss.CreateQuery( " fromStudentasstuwherestu.Age>:studentAge " );
query.SetInt32( " studentAge " , 20 );
return query.List();
}
SessionQuicker的好处是避免了每次数据访问写重复的try...catch...finally块,但是与前面理想的using块比起来,优雅性就要差许多。
我期待着有人提出更优雅的解决方案!