2012-07-24 119 views
4

通過分配SaveChanges事件處理程序來實現OnContext創建用於審計我已經嘗試了許多不同的方法並查看了不同的帖子,但仍未遇到這種審計方式的解決方案。以下是我的DBContext模板文件。我通過添加OnContextCreated()部分方法來定製它,並將SavingChanges事件分配給我的OnSavingChanges事件處理程序。使用EF 4.1 DBContext

namespace ARSystem.Models 
{ 
    public partial class ARSEntities : ObjectContext 
    { 
     public ARSEntities() 
      : base("name=ARSEntities") 
     { 
     } 

     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      throw new UnintentionalCodeFirstException(); 
     } 

     public string UserName { get; set; } 
     List<DBAudit> auditTrailList = new List<DBAudit>(); 

     public enum AuditActions 
     { 
      I, 
      U, 
      D 
     } 

     partial void OnContextCreated() 
     { 
      this.SavingChanges += new EventHandler(OnSavingChanges); 
     } 

     public void OnSavingChanges(object sender, EventArgs e) 
     { 
      IEnumerable<ObjectStateEntry> changes = this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified); 
      foreach (ObjectStateEntry stateEntryEntity in changes) 
      { 
       if (!stateEntryEntity.IsRelationship && 
         stateEntryEntity.Entity != null && 
          !(stateEntryEntity.Entity is DBAudit)) 
       {//is a normal entry, not a relationship 
        DBAudit audit = this.AuditTrailFactory(stateEntryEntity, UserName); 
        auditTrailList.Add(audit); 
       } 
      } 

      if (auditTrailList.Count > 0) 
      { 
       foreach (var audit in auditTrailList) 
       {//add all audits 
        this.AddToDBAudit(audit); 
       } 
      } 
     } 

     private DBAudit AuditTrailFactory(ObjectStateEntry entry, string UserName) 
     { 
      DBAudit audit = new DBAudit(); 
      audit.AuditId = Guid.NewGuid().ToString(); 
      audit.RevisionStamp = DateTime.Now; 
      audit.TableName = entry.EntitySet.Name; 
      audit.UserName = UserName; 

      if (entry.State == EntityState.Added) 
      {//entry is Added 
       audit.NewData = GetEntryValueInString(entry, false); 
       audit.Actions = AuditActions.I.ToString(); 
      } 
      else if (entry.State == EntityState.Deleted) 
      {//entry in deleted 
       audit.OldData = GetEntryValueInString(entry, true); 
       audit.Actions = AuditActions.D.ToString(); 
      } 
      else 
      {//entry is modified 
       audit.OldData = GetEntryValueInString(entry, true); 
       audit.NewData = GetEntryValueInString(entry, false); 
       audit.Actions = AuditActions.U.ToString(); 

       IEnumerable<string> modifiedProperties = entry.GetModifiedProperties(); 
       //assing collection of mismatched Columns name as serialized string 
       audit.ChangedColumns = XMLSerializationHelper.XmlSerialize(modifiedProperties.ToArray()); 
      } 

      return audit; 
     } 

     private string GetEntryValueInString(ObjectStateEntry entry, bool isOrginal) 
     { 
      if (entry.Entity is EntityObject) 
      { 
       object target = CloneEntity((EntityObject)entry.Entity); 
       foreach (string propName in entry.GetModifiedProperties()) 
       { 
        object setterValue = null; 
        if (isOrginal) 
        { 
         //Get orginal value 
         setterValue = entry.OriginalValues[propName]; 
        } 
        else 
        { 
         //Get orginal value 
         setterValue = entry.CurrentValues[propName]; 
        } 
        //Find property to update 
        PropertyInfo propInfo = target.GetType().GetProperty(propName); 
        //update property with orgibal value 
        if (setterValue == DBNull.Value) 
        {// 
         setterValue = null; 
        } 
        propInfo.SetValue(target, setterValue, null); 
       }//end foreach 

       XmlSerializer formatter = new XmlSerializer(target.GetType()); 
       XDocument document = new XDocument(); 

       using (XmlWriter xmlWriter = document.CreateWriter()) 
       { 
        formatter.Serialize(xmlWriter, target); 
       } 
       return document.Root.ToString(); 
      } 
      return null; 
     } 

     public EntityObject CloneEntity(EntityObject obj) 
     { 
      DataContractSerializer dcSer = new DataContractSerializer(obj.GetType()); 
      MemoryStream memoryStream = new MemoryStream(); 

      dcSer.WriteObject(memoryStream, obj); 
      memoryStream.Position = 0; 

      EntityObject newObject = (EntityObject)dcSer.ReadObject(memoryStream); 
      return newObject; 
     } 

     public DbSet<Student> Students { get; set; } 
     public DbSet<User> Users { get; set; } 
     public DbSet<aspnet_Applications> aspnet_Applications { get; set; } 
     public DbSet<aspnet_Membership> aspnet_Membership { get; set; } 
     public DbSet<aspnet_Roles> aspnet_Roles { get; set; } 
     public DbSet<aspnet_SchemaVersions> aspnet_SchemaVersions { get; set; } 
     public DbSet<aspnet_Users> aspnet_Users { get; set; } 
     public DbSet<vw_aspnet_Applications> vw_aspnet_Applications { get; set; } 
     public DbSet<vw_aspnet_MembershipUsers> vw_aspnet_MembershipUsers { get; set; } 
     public DbSet<vw_aspnet_Roles> vw_aspnet_Roles { get; set; } 
     public DbSet<vw_aspnet_Users> vw_aspnet_Users { get; set; } 
     public DbSet<vw_aspnet_UsersInRoles> vw_aspnet_UsersInRoles { get; set; } 
     public DbSet<Cours> Courses { get; set; } 
     public DbSet<Enrollment> Enrollments { get; set; } 
     public DbSet<Modules> Modules { get; set; } 
     public DbSet<EnrollmentsByCourse> EnrollmentsByCourse { get; set; } 
     public DbSet<EnrollmentsByCourseAudit> EnrollmentsByCourseAudit { get; set; } 
     public DbSet<DBAudit> DBAudit { get; set; } 
    } 
} 

然而,當我編譯,我得到的錯誤消息:

錯誤1 'ARSystem.Models.ARSEntities.OnModelCreating(System.Data.Entity.DbModelBuilder)':沒有合適的方法發現重寫C:\用戶\ mngum \文件\的Visual Studio 2010 \項目\ ARSystem \ ARSystem \模型\ ARSystem.Context.cs 35 33 ARSystem

我不能看到的DbContext元數據類的OnContextCreated方法,但我可以在edmx設計器中找到它。請讓我知道如何執行OnContextCreated()方法,以便我可以覆蓋SavingChanges事件以進行審計。

回答

8

DbContext沒有OnContextCreated事件,但這不是問題,因爲您不需要它來實現相同。用DbContext代替SaveChanges方法是可覆蓋的。因此,而不是你的OnSavingChanges事件處理程序的使用:

public override int SaveChanges() 
{ 
    // custom code... 

    return base.SaveChanges(); 
} 

每當調用ARSEntities.SaveChanges()你調用基DbContextARSEntities必須從當然DbContext得出的base.SaveChanges(),然後才能執行自定義操作此方法將被調用。)

您也可以訪問底層ObjectContextDbContext

public override int SaveChanges() 
{ 
    var objectContext = ((IObjectContextAdapter)this).ObjectContext; 

    // use methods and properties of ObjectContext now like 
    // objectContext.ObjectStateManager, etc. 

    // custom code... 

    return base.SaveChanges(); 
} 

這裏是一個類似的問題和答案變更審計與EF 4.1/DbContext

Entity Framework 4.1 DbContext Override SaveChanges to Audit Property Change

+0

你會如何編寫單元測試的自定義代碼? – 2016-04-28 16:03:02