Entity Framework 6 Batch Updates and AuditLog using Entity Framework Extended

entity-framework entity-framework-5 entity-framework-6 entity-framework-extended

Question

For some batch updates and batch deletes, I'm using Entity Framework 6 and EntityFramework Extended. The batch updates and deletes function OK, but I also need to know which entities were changed or removed (i.e. the current and previous values). Using the AuditLogger offered by EntityFramework, I reasoned. The information on the entities that were changed or removed would be provided to me by Extended, but this does not appear to be the case. As an illustration, the following code, i.e.

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

This straightforward batch update will change all addressIds to1190 If I look, Ichanges.Entities , it returns an empty list with a count of 0.

What I anticipated was thatchanges.Entities would include all of the "old" entities with the previous addressId values.1190 .

Am I incorrect, or is this the right way to behave? When utilizing Entity Framework Extended batch update / delete, how can I obtain an audit log of all modified entities?

Thanks

1
3
7/31/2014 5:29:42 PM

Accepted Answer

You must make the Auditor available.

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

simply include it where your app is initially launched. For instance, Global.asax.cs

edited

As far as I'm aware, EF.Extended cannot retrieve past values. Here is what I would do:

override the Context's SaveChanges function

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;
    }

likewise provide a process audit logging method:

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 may employ AutoMapper.

Another technique to obtain base entity's type:

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

Hope it'll be useful to you.

3
11/25/2014 1:15:00 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow