通过使用EF 4.1 DBContext为SaveChanges分配一个事件处理程序来实现OnContextCreated以进行审计

时间:2012-07-24 16:38:59

标签: asp.net-mvc entity-framework edmx-designer

我尝试了许多不同的方法并查看了不同的帖子,但仍未找到这种审核方式的解决方案。下面是我的DBContext模板文件。我通过添加OnContextCreated()部分方法对其进行了自定义,并将SavingChanges事件分配给我的OnSavingChanges事件处理程序。

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:\ Users \ mngum \ Documents \ Visual Studio 2010 \ Projects \ ARSystem \ ARSystem \ Models \ ARSystem.Context.cs 35 33 ARSystem

我无法在DBContext元数据类中看到OnContextCreated方法,但我可以在edmx设计器中找到它。请告诉我如何实施OnContextCreated()方法,以便我可以覆盖SavingChanges事件以进行审核。

1 个答案:

答案 0 :(得分:8)

DbContext没有OnContextCreated事件,但这不是问题,因为您不需要它来实现相同的目标。相反,使用DbContext SaveChanges方法可以覆盖。因此,您使用的不是OnSavingChanges事件处理程序:

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

    return base.SaveChanges();
}

每当您致电ARSEntities.SaveChanges()时都会调用此方法,并且您可以在致电基座base.SaveChanges()的{​​{1}}之前执行自定义操作(DbContext必须来自ARSEntities {1}}当然。)

您还可以从DbContext

访问基础ObjectContext
DbContext

以下是关于使用EF 4.1 / 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(); } 进行变更审核的类似问题和答案:

Entity Framework 4.1 DbContext Override SaveChanges to Audit Property Change