我的前一篇随笔
《使用NHibernate中的拦截器》中简单讲述了如何使用接口IInterceptor拦截CRUD操作。但没有区分开新增和修改操作。
对于public bool OnSave(object entity, object id, object[] state, string[] propertyNames,
NHibernate.Type.IType[] types)会在Insert new object之前触发,而public void PreFlush(System.Collections.ICollection entities)则是Update old Object之前和Insert New Object之后都会触发的。为了记录下来明确的实体的insert和update操作,需要将其区分开。所以我查看了NHIbernate的源码,发现Insert new object到了调用PreFlush后,其ID字段(属性)就有值了,而在OnSave时是为0或者null或者其它配置文件中定义的unsaved-value。通常为了简单,都是使用子动增长的字段作为ID的。所以我写了下面的代码来分别记录“新增”和“修改”的操作:
/**/
/// <summary>
/// CRUD日志记录类
/// </summary>
public
class
LogInterceptor : IInterceptor
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private Hashtable _entity = null;
private Type _entityType = null;
private IEntityManager manager = null;
public LogInterceptor()
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
manager = EntityManager.CreateEntityManager();
}
![ContractedSubBlock.gif](/Images/OutliningIndicators/ContractedSubBlock.gif)
IInterceptor 成员#region IInterceptor 成员
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
//省略其他必须实现的方法
public bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// Insert New Object之前会触发
if ( manager.Factory != null )
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this._entityType = entity.GetType();
this._entity = Copy(state,propertyNames);
}
else
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this._entity = null;
this._entityType = null;
}
this.AddLog(entity,id,state,propertyNames,"新增");
return false;
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public void OnDelete(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.AddLog(entity,id,state,propertyNames,"删除");
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
public void PreFlush(System.Collections.ICollection entities)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// Update old Object之前会触发
// Insert New Object之后会触发
if ( entities.Count >0 )
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
//过滤掉Insert New Object
AddLog(entities,"修改");
}
}
#endregion
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
private Hashtable Copy(object[] state, string[] propertyNames)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
_entity = new Hashtable();
for ( int i=0;i<state.Length;i++)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
_entity.Add(propertyNames[i],state[i]);
}
return _entity;
}
private void AddLog(object entity,object entityID,object[] state,string[] propertyNames,string operType)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
try
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
//如果是日志类自己的话,就不再记录了
if ( entity.GetType() == typeof(DAL.SMS.SM_Log))
return;
Log log = Log.CreateLog();
StringBuilder states = new StringBuilder();
for ( int i=0;i<state.Length;i++)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if ( state[i] == null )
continue;
string pName = propertyNames[i];
if ( log.dsEntity != null )
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
DataRow[] rows = log.dsEntity.Tables[0].Select("Entity='"+entity.ToString()+"' and Property='"+pName+"'");
if ( rows != null && rows.Length>0 )
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
pName = rows[0]["PropertyName"].ToString();
}
}
states.Append("|| "+pName+"--"+state[i].ToString()+" ||\t\r");
}
log.Add(entity.ToString(),entityID.ToString(),states.ToString(),operType);
}
catch
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{}
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
private void AddLog(ICollection entities,string operType)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
try
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
IEnumerator e = entities.GetEnumerator();
while (e.MoveNext())
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Type type = e.Current.GetType();
if ( type == typeof(DAL.SMS.SM_Log))
continue;
PropertyInfo[] pi = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
string[] propertyNames = new string[pi.Length];
object[] state = new object[pi.Length];
object id = e.Current;
string idName = manager.Factory.GetPersister(type).IdentifierPropertyName;
if (this._entityType != null && type == _entityType)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
bool isNewObject = true;
for (int i=0;i<pi.Length;i++)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if ( pi[i].Name != idName)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
object v = pi[i].GetValue(e.Current,null);
isNewObject &= (_entity[pi[i].Name].ToString() == v.ToString());
}
}
if ( isNewObject )
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
continue;
}
}
for(int i=0;i<pi.Length;i++)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
propertyNames[i]= pi[i].Name;
state[i]= pi[i].GetValue(e.Current,null);
if ( pi[i].Name == idName )
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
id = state[i];
}
}
this.AddLog(e.Current,id,state,propertyNames,operType);
this._entity = null;
this._entityType = null;
}
}
catch
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{}
}
}
上面代码中的
private
IEntityManager manager
=
null
;是一个用来管理session的管理器,提供了一个属性public ISessionFactoryImplementor Factory,通过该属性才能方面地得知实体类的ID属性的名字:
public
sealed
class
EntityManager : IEntityManager
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private static ISessionFactory nSessionFactory = null;
//
public ISessionFactoryImplementor Factory
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return nSessionFactory as ISessionFactoryImplementor;}
}
}
获得ID属性的名字:
string
idName
=
manager.Factory.GetPersister(type).IdentifierPropertyName;
于是现在可以比较粗略地记录下CRUD操作了……