سؤال

I am using Entity Framework 6 and I am using EntityFramework Extended to perform some batch updates and batch deletes. The batch updates and batch deletes work OK however I also need to know the entities that were updated / deleted (i.e. the current and previous values). I thought that using the AuditLogger provided by EntityFramework.Extended would provide me with the details of the entities that where updated or deleted however this does not seem to be the case. For example, using the code below i.e.

var auditor =dbContext.BeginAudit();
dbContext.Addresses.Update(ent => new Address { AddressId = 1190 });
dbContext.SaveChanges();
var changes = auditor.LastLog;

This is simple batch update to update all addressIds to 1190. If I inspect changes.Entities, it returns a Count of 0 i.e. an empty list.

What I was expecting was that changes.Entities would contain all the 'old' entities with the old values before the addressId was changed to 1190.

Am I mistaken or is this indeed the correct behaviour? How can I get an audit log of all updated entities when using Entity framework Extended batch update / delete

Thanks

هل كانت مفيدة؟

المحلول

You should enable the Auditor

var auditConfiguration = AuditConfiguration.Default;
auditConfiguration.IncludeRelationships = true;
auditConfiguration.LoadRelationships = true;
auditConfiguration.DefaultAuditable = true;

just add it to place where your app is initialized, Global.asax.cs for example

edited

Far as I know you can't get old values using EF.Extended. Here is my solution:

override SaveChanges method in the Context

public override int SaveChanges()
    {
        return SaveChanges(false);
    }

    public int SaveChanges(bool disableAudit)
    {
        var result = -1;
        try
        {
            if (!disableAudit)
            {
                foreach (var entity in ChangeTracker.Entries().Where(x => x.State == EntityState.Added ||
                                                                          x.State == EntityState.Modified ||
                                                                          x.State == EntityState.Deleted))
                {
                    ProccessAuditLog(entity);
                }
            }
        }
        catch (Exception ex)
        {
            // handle the ex here
        }
        finally
        {
            //save changes
            result = base.SaveChanges();
        }

        return result;
    }

and add method to process audit logging:

private void ProccessAuditLog(DbEntityEntry entry)
    {
        var entity = entry.Entity;
        var entityType = GetEntityType(entity.GetType());

        var oldValue = Activator.CreateInstance(entityType); ;
        if (entry.State == EntityState.Modified)
        {
            // entry.OriginalValues doesn't load navigation properties for changed entity so we should reload the object from db to get it
            // save current values
            var newValue = Activator.CreateInstance(entityType);
            Mapper.DynamicMap(entity, newValue, entity.GetType(), entityType);

            // reload old values for entity from the db
            entry.Reload();
            Mapper.DynamicMap(entry.Entity, oldValue, entity.GetType(), entityType);

            // revert reloading changes in entity
            entry.CurrentValues.SetValues(newValue);
            entry.OriginalValues.SetValues(oldValue);
            entry.State = EntityState.Modified;
            entity = newValue;
        }

        if (entry.State == EntityState.Deleted)
        {
            // reload old values for entity from the db
            entry.Reload();
            Mapper.DynamicMap(entry.Entity, oldValue, entity.GetType(), entityType);

            // revert reloading changes in entity
            entry.OriginalValues.SetValues(oldValue);
            entry.State = EntityState.Deleted;
            entity = null;
        }

        // here is you can proccess old entity in 'oldValue' and new entity in 'entity'
        // then save your log to db using SaveChanges(true) to prevent StackOverFlow exception
    }

As Mapper you can use AutoMapper

method to get base entity's type instead proxy type:

private Type GetEntityType(Type entityType)
        {
            return entityType.BaseType != null && entityType.Namespace == "System.Data.Entity.DynamicProxies"
                    ? entityType.BaseType
                    : entityType;
        }

Hope it will help you

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top