Реализация OnContextCreated для аудита путем назначения SaveChanges обработчика событий с использованием EF 4.1 DBContext

Я пробовал много разных способов и просматривал разные посты, но до сих пор не нашел решения для такого способа аудита. Ниже мой файл шаблона 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

Я не вижу метода OnContextCreated в классе метаданных DBContext, но могу найти его в конструкторе edmx. Пожалуйста, дайте мне знать, как я могу реализовать OnContextCreated() метод такой, что я могу переопределить SavingChanges событие для целей аудита.

1 ответ

Решение

DbContext не имеет OnContextCreated событие, но это не проблема, потому что вам не нужно, чтобы достичь того же. Вместо DbContext SaveChanges метод переопределим. Так что вместо твоего OnSavingChanges используемый вами обработчик событий:

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

    return base.SaveChanges();
}

Этот метод будет вызываться всякий раз, когда вы звоните ARSEntities.SaveChanges() и вы можете выполнять пользовательские действия, прежде чем позвонить base.SaveChanges() базы DbContext (ARSEntities должен быть получен из DbContext конечно.)

Вы также можете получить доступ к основному ObjectContext от DbContext:

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 переопределяет SaveChanges для аудита изменения свойств

Другие вопросы по тегам