web-dev-qa-db-de.com

Entity Framework 6: Änderungen prüfen / verfolgen

Ich habe mein Kernprojekt in C #.

Ich arbeite an einer Datenbank, in der einige Tabellen die Spalten "user_mod" und "date_mod" für "sign who" und "user_new" enthalten.

Meine Frage: gibt es eine Möglichkeit, dies zu zentralisieren und diese Daten automatisch einzufügen, wo ich die Instanz von dbContext erstelle?

Wenn nicht, verwende ich ein Audit-Trail-Tool. Ich habe einige davon gesehen, aber es gibt ein Problem: Für alle ist Code in meinem Modell erforderlich. Aber ich möchte nicht in mein Modell schreiben, denn wenn ich es ändern muss, werde ich die Mods verlieren. Ist es möglich, einen Audit-Trail für EF6 zu verwenden, ohne in die Modelldatei (en) zu schreiben? Wie?

BEARBEITEN:

Mein Versuch, die saveChanges zu überschreiben.

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

UPDATE: Ich habe die Lösung hier zusammengefasst.

46
Piero Alberto

Bei Verwendung von DbContext in EF6 können Sie ChangeTracker in SaveChanges überschreiben, um hinzugefügte/geänderte Entitäten eines benutzerdefinierten Typs zu suchen, z. B. 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

Es gibt eine Möglichkeit, dies zu tun: Sie können eine Teilklasse mit demselben Namen wie Ihr Objektkontext erstellen und eine Überschreibung der SaveChanges -Methode implementieren. In diesem Override können Sie alle Änderungen anzeigen, die in den DB übertragen werden, und diese verarbeiten.

Sie können sie beliebig verarbeiten. Im folgenden Beispiel habe ich eine Schnittstelle IAutoTimestampEntity erstellt, die ein Erstellungsdatum und ein Änderungsdatum enthält. Jedes Objekt dieses Typs wird zum Zeitpunkt der Änderung automatisch aktualisiert.

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

Sie können dasselbe Prinzip anwenden oder den Typ jeder geänderten Entität detailliert betrachten. Ich mag den deklarativen Aspekt der Schnittstelle. Hiermit können Sie einen Aspekt der Automatisierung explizit herausstellen, anstatt dies von der EF-Ebene unbemerkt ausführen zu lassen.

Wenn Sie ein DbContext anstelle eines ObjectContext haben, setzen Sie Ihr DbContext auf IObjectContextAdapter, um auf das ObjectStateManager zuzugreifen.

5
samy