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と、Count 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
    }

AutoMapperMapperを使用できるよう

プロキシ タイプの代わりにベース エンティティのタイプを取得するメソッド:

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

それがあなたを助けることを願っています

于 2014-11-21T09:23:08.500 に答える