3

我正在使用 Entity Framework 6,并且正在使用 EntityFramework Extended 来执行一些批量更新和批量删除。批量更新和批量删除工作正常,但是我还需要知道被更新/删除的实体(即当前和以前的值)。我认为使用 EntityFramework.Extended 提供的 AuditLogger 可以为我提供更新或删除的实体的详细信息,但情况似乎并非如此。例如,使用下面的代码,即

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

这是将所有 addressId 更新为 的简单批量更新1190。如果我检查changes.Entities,它返回一个 0 的计数,即一个空列表。

我所期望的是,changes.Entities在 addressId 更改为之前,它将包含所有具有旧值的“旧”实体1190

我弄错了还是这确实是正确的行为?使用实体框架扩展批量更新/删除时如何获取所有更新实体的审核日志

谢谢

4

1 回答 1

3

您应该启用审核员

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

只需将其添加到您的应用程序初始化的位置,例如 Global.asax.cs

已编辑

据我所知,您无法使用 EF.Extended 获取旧值。这是我的解决方案:

覆盖 Context 中的 SaveChanges 方法

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

并添加处理审计日志的方法:

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
    }

Mapper可以使用AutoMapper

获取基本实体类型而不是代理类型的方法:

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

希望对你有帮助

于 2014-11-21T09:23:08.500 回答