在NHibernate中拦截器(IInterceptor)的使用
序言
在NHibernate中如果想对CRUD进行一些记录日志这样的操作的话,可以使用IInterceptor来达到目的。这个拦截器从我知道的0.3版到0.6版还没有改变过。
其实还有另外一个接口可用:ILifecycle,它大概是这样:
public NHibernate.LifecycleVeto OnUpdate(ISession s){}
public void OnLoad(ISession s, object id){}
public NHibernate.LifecycleVeto OnSave(ISession s){}
public NHibernate.LifecycleVeto OnDelete(ISession s){}
但是你必须在每个实体类上实现该接口,一般我们的系统中都有大量的实体类,所以实现ILifecycle将是一件费力不讨好的事情。而IInterceptor有着和ILifecycle类似的方法:
public int[] FindDirty(object entity, object id,
object[] currentState, object[] previousState, string[]
propertyNames, NHibernate.Type.IType[] types){}
public object Instantiate(Type type, object id){}
public bool OnFlushDirty(object entity, object id, object[]
currentState, object[] previousState, string[] propertyNames,
NHibernate.Type.IType[] types){}
public object IsUnsaved(object entity){}
public bool OnLoad(object entity, object id, object[] state, string[]
propertyNames, NHibernate.Type.IType[] types){}
// Insert New Object之前会触发;Update old Object之前会触发
public bool OnSave(object entity, object id, object[] state, string[]
propertyNames, NHibernate.Type.IType[] types){}
public void OnDelete(object entity, object id, object[] state, string[]
propertyNames, NHibernate.Type.IType[] types){}
// Update old Object之前会触发; Insert New Object之后会触发
public void PreFlush(System.Collections.ICollection entities){}
public void PostFlush(System.Collections.ICollection entities){}
我们看到IInterceptor有着比ILifecycle更多的方法,而且IInterceptor是针对Session中的每个实体对象的。但是不便的是,我们并不能阻止事件,只能修改对象的状态(object[] state),返回布尔值来影响最终结果。这个比起AOP就显然差得远了,我们看看NHibernate的源代码也能看出这一点。
具体用法
1、写一个实现IInterceptor接口的类
///
/// 日志记录类
///
public class LogInterceptor : IInterceptor
{
#region IInterceptor 成员
…
public bool OnLoad(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
{
//AddLog(entity,id,state,propertyNames,"加载");
return false;
}
public bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
{
//AddLog(entity,id,state,propertyNames,"保存");
return false;
}
public void OnDelete(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
{
//AddLog(entity,id,state,propertyNames,"删除");
}
public void PreFlush(System.Collections.ICollection entities)
{
//AddLog(entities,"保存");
}
#endregion
private void AddLog(object entity,object entityID,object[] state,string[] propertyNames,string operType)
{
//记录日志。。。
}
}
2、将实现IInterceptor的类和Session联系起来
private static ISessionFactory nSessionFactory = null;
//。。。
public ISession GetSession()
{
//...
return nSessionFactory.OpenSession(new LogInterceptor());
}
现在所有的CRUD都可以被记录了。当然使用这个来做权限检查是不能满足需要的。
注意任何在Session上执行的CRUD都会被拦截器拦截到的,所以还要避免日志记录类的CRUD又被记录了。
体会
由于系统运行的时候会有大量的CRUD操作,使用这个拦截器进行拦截去拦截每个CRUD的话,将会产生大量的记录,并且还会拦截到日志记录类的CRUD。为了具有针对性的做一些日志记录,可以在记录前多做一些判断,并且最好能记录下让用户看得懂的信息(这需要知道每个实体类的业务含义了)。 这个拦截器当然和AOP不可同日而语了,但它还是可以帮我用很少的代码做一些事情。