使用NHibernate中的拦截器(续)

我的前一篇随笔《使用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
    
{
                
        
private Hashtable _entity = null;
        
private Type _entityType = null;
        
private IEntityManager manager = null;
        
public LogInterceptor()
        
{
            manager 
= EntityManager.CreateEntityManager();
        }

        
IInterceptor 成员

        
private Hashtable Copy(object[] state, string[] propertyNames)
        
{
            _entity 
= new Hashtable();
            
for ( int i=0;i<state.Length;i++)
            
{
                _entity.Add(propertyNames[i],state[i]);
            }

            
return _entity;
        }

        
private void AddLog(object entity,object entityID,object[] state,string[] propertyNames,string operType)
        
{
            
try
            
{
                                
//如果是日志类自己的话,就不再记录了
                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++)
                
{
                    
if ( state[i] == null )
                        
continue;
                    
string pName = propertyNames[i];
                    
if ( log.dsEntity != null )
                    
{
                        DataRow[] rows 
= log.dsEntity.Tables[0].Select("Entity='"+entity.ToString()+"' and Property='"+pName+"'");
                        
if ( rows != null && rows.Length>0 )
                        
{
                            pName 
= rows[0]["PropertyName"].ToString();
                        }

                    }

                    states.Append(
"|| "+pName+"--"+state[i].ToString()+" ||\t\r");
                }

                log.Add(entity.ToString(),entityID.ToString(),states.ToString(),operType);
            }

            
catch
            
{}
        }


        
private void AddLog(ICollection entities,string operType)
        
{
            
try
            
{
                IEnumerator e 
= entities.GetEnumerator();
                
while (e.MoveNext())
                
{
                    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)
                    
{
                        
bool isNewObject = true;
                        
for (int i=0;i<pi.Length;i++)
                        
{
                            
if ( pi[i].Name != idName)
                            
{
                                
object v = pi[i].GetValue(e.Current,null);
                                isNewObject 
&= (_entity[pi[i].Name].ToString() == v.ToString());
                            }

                        }

                        
if ( isNewObject )
                        
{
                            
continue;
                        }

                    }

                    
for(int i=0;i<pi.Length;i++)
                    
{
                        propertyNames[i]
= pi[i].Name;
                        state[i]
= pi[i].GetValue(e.Current,null);
                        
if ( pi[i].Name == idName )
                        
{
                            id 
= state[i];
                        }

                    }

                    
this.AddLog(e.Current,id,state,propertyNames,operType);
                    
this._entity = null;
                    
this._entityType = null;
                }

            }

            
catch
            
{}
        }

    }

上面代码中的private IEntityManager manager = null;是一个用来管理session的管理器,提供了一个属性public ISessionFactoryImplementor Factory,通过该属性才能方面地得知实体类的ID属性的名字:
public sealed class EntityManager : IEntityManager
{
   
private static ISessionFactory nSessionFactory = null;
   
//
   public ISessionFactoryImplementor Factory
   
{
    
get {return nSessionFactory as ISessionFactoryImplementor;}
    }

}

获得ID属性的名字:
string idName = manager.Factory.GetPersister(type).IdentifierPropertyName;

于是现在可以比较粗略地记录下CRUD操作了……
posted @ 2005-01-21 13:29  风满袖  阅读(1821)  评论(0编辑  收藏  举报