web-dev-qa-db-ja.com

Entity Framework 6:変更の監査/追跡

私のコアプロジェクトはC#にあります。

私はデータベースに取り組んでいます。いくつかのテーブルには、「data_new」と「user_new」と同じように誰がいつMODを作成したかを示す「user_mod」列と「date_mod」列があります。

私の質問:これを集中化し、dbContextのインスタンスを作成するこのデータを自動的に挿入する方法はありますか?

そうでない場合は、監査証跡ツールを使用します。私はこれらのいくつかを見てきましたが、問題があります。これらすべては、私のモデルにいくつかのコードを必要とします。しかし、モデルを書きたくないのは、モデルを変更する必要がある場合、MODが失われるためです。モデルファイルに書き込まずにEF6の監査証跡を使用することは可能ですか?どうやって?

編集:

SaveChangesをオーバーライドしようとしています。

public partial class PieEntities : DbContext
{
    public override int SaveChanges(System.Data.Objects.SaveOptions options)
    {
        var timestamp = DateTime.Now;

        EntityState es = EntityState.Added;
        ObjectStateManager o = new ObjectStateManager();

        foreach (ObjectStateEntry entry in o.GetObjectStateEntries(EntityState.Added ))  {
            if (entry.Entity.GetType() == typeof(TabImpianti)) {
                TabImpianti impianto = entry.Entity as TabImpianti;
                impianto.DATA_INS = timestamp;
                impianto.DATA_MOD = timestamp;
                string u = mdlImpostazioni.p.UserName;
                impianto.USER_INS = u;
                impianto.USER_MOD = u;
            }
        }
        return base.SaveChanges(options);
    }
}

更新: ここでの解決策をまとめました

46
Piero Alberto

EF6のDbContextを使用している場合、ChangeTrackerオーバーライドでSaveChangesを使用して、IAuditedEntityなどのカスタムタイプの追加/変更されたエンティティを検索できます。

public interface IAuditedEntity {
  string CreatedBy { get; set; }
  DateTime CreatedAt { get; set; }
  string LastModifiedBy { get; set; }
  DateTime LastModifiedAt { get; set; }
}

public override int SaveChanges() {
  var addedAuditedEntities = ChangeTracker.Entries<IAuditedEntity>()
    .Where(p => p.State == EntityState.Added)
    .Select(p => p.Entity);

  var modifiedAuditedEntities = ChangeTracker.Entries<IAuditedEntity>()
    .Where(p => p.State == EntityState.Modified)
    .Select(p => p.Entity);

  var now = DateTime.UtcNow;

  foreach (var added in addedAuditedEntities) {
    added.CreatedAt = now;
    added.LastModifiedAt = now;
  }

  foreach (var modified in modifiedAuditedEntities) {
    modified.LastModifiedAt = now;
  }

  return base.SaveChanges();
}
69
Alaa Masoud
16
Bilal Fazlani

その方法は1つあります。オブジェクトコンテキストと同じ名前の部分クラスを作成し、SaveChangesメソッドのオーバーライドを実装できます。このオーバーライドでは、DBにプッシュされるすべての変更を確認して処理できます。

これらは好きな方法で処理できます。次の例では、作成日と変更日を含むインターフェイスIAutoTimestampEntityを作成しました。このタイプのオブジェクトは、変更時に自動的に更新されます。

public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
    var timestamp = DateTime.Now;

    foreach (var InsertedAutoTimestampEntity in ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added).Select(ose => ose.Entity).OfType<IAutoTimestampEntity>())
    {
        InsertedAutoTimestampEntity.CreationDate = timestamp;
        InsertedAutoTimestampEntity.ModificationDate = timestamp;
    }

    foreach (var UpdatedAutoTimestampEntity in ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified).Select(ose => ose.Entity).OfType<IAutoTimestampEntity>())
    {
        UpdatedAutoTimestampEntity.ModificationDate = timestamp;
    }

    return base.SaveChanges(options);
}

同じ原則を使用することも、変更された各エンティティのタイプを詳細に調べることもできます。しかし、インターフェイスの宣言的な側面が好きです。自動化の1つの側面を、EFレイヤーによってサイレントに実行するのではなく、明示的に公開できます。

DbContextの代わりにObjectContextがある場合は、DbContextIObjectContextAdapterにキャストしてObjectStateManagerにアクセスします

5
samy