2013-12-20 13 views
5

in meiner DbContext-Unterklasse Ich habe die SaveChanges() -Methode überschrieben, damit ich eine Art Trigger-ähnliche Funktionalität implementieren kann (bevor die Änderungen tatsächlich gespeichert werden). Nun, in einigen dieser Trigger ist es notwendig zu erkennen, ob bestimmte Beziehungen geändert haben, unabhängig von viele zu viele, eins zu eins/Null usw.Entity Framework 6: Beziehungsänderungen erkennen

Ich habe eine Reihe von Beiträgen im Internet gelesen , einschließlich einiger auf dieser Site, die erwähnen, dass die DbContext API keine Möglichkeit offen lässt, Beziehungsinformationen zu erhalten. Allerdings sollte ObjectContext in der Lage sein.

Mein Savechanges-Methode:

public override int SaveChanges() 
{ 
    IEntity entity; 
    ChangeTracker.DetectChanges(); 

    var stateManager = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager; 
    var added = stateManager.GetObjectStateEntries(EntityState.Added).ToList(); 
    var updated = stateManager.GetObjectStateEntries(EntityState.Modified).ToList(); 
    var deleted = stateManager.GetObjectStateEntries(EntityState.Deleted).ToList(); 
    var unchanged = stateManager.GetObjectStateEntries(EntityState.Unchanged).ToList(); 

    while ((entity = _entitiesRequiringTriggering.FirstOrDefault(x => x.Value).Key) != null) 
    { 
     _entitiesRequiringTriggering[entity] = false; 
     var entry = ChangeTracker.Entries<IEntity>().SingleOrDefault(x => x.State != EntityState.Unchanged && x.Entity == entity); 
     if (entry == null) continue; 
     var trigger = Triggers.Triggers.GetTriggerForEntity(entry.Entity, this); 
     if (trigger == null) continue; 
     trigger.BeforeSave(entry.Entity); 
     switch (entry.State) 
     { 
      case EntityState.Added: 
       trigger.BeforeAdd(entry.Entity); 
       break; 
      case EntityState.Modified: 
       trigger.BeforeUpdate(entry.Entity); 
       break; 
      case EntityState.Deleted: 
       trigger.BeforeDelete(entry.Entity); 
       break; 
     } 
    } 
    return base.SaveChanges(); 
} 

Beachten Sie die vier Variablen , hinzugefügt aktualisiert, gelöscht und unverändert. Nach dem, was ich bisher gefunden habe, soll die GetObjectStateEntries eine Auflistung von ObjectStateEntry zurückgeben, die eine Eigenschaft IsRelationship hat.

ich den folgenden Code in einer Testanwendung ausführen:

using (var db = container.Resolve<IDatabaseContext>()) 
{ 
    var cus = db.Query<Customer>().Single(x => x.Id == 1); 
    var newAddress = db.Query<Address>().Single(x => x.Id == 5); 

    cus.Address = newAddress; //also sets the foreign key property Customer.AddressId to its new corresponding value 
    db.SaveChanges(); 
} 

Wenn ich den Code in Savechanges nach diesem Anruf prüfen, erhalte ich, was erwartet wurde: ein Ergebnis in der Liste aktualisiert, der Kunde Objekt. Aber zu keinem Zeitpunkt bekomme ich jemals einen ObjectStateEntry für die Beziehung (one-to-one) Customer_Address.

Ich muss in der Lage sein, wie zuvor beschrieben zu erkennen, wenn sich die Beziehung geändert hat. Für normale skalare Eigenschaften würden Sie dies tun:

var changed = DbEntry.Property(x => x.Name).OriginalValue == DbEntry.Property(x => x.Name).CurrentValue; 

Aber für Referenzobjekte, die nicht offensichtlich nicht funktioniert. Irgendwelche Ideen?

Antwort

9

können Sie diese ExtensionMethod verwenden, um eine Liste von Beziehungen zu erhalten, die

geändert
public static class DbContextExtensions 
{ 
    public static IEnumerable<Tuple<object, object>> GetRelationships(
     this DbContext context) 
    { 
     return GetAddedRelationships(context) 
       .Union(GetDeletedRelationships(context)); 
    } 

    public static IEnumerable<Tuple<object, object>> GetAddedRelationships(
     this DbContext context) 
    { 
     return GetRelationships(context, EntityState.Added, (e, i) => e.CurrentValues[i]); 
    } 

    public static IEnumerable<Tuple<object, object>> GetDeletedRelationships(
     this DbContext context) 
    { 
     return GetRelationships(context, EntityState.Deleted, (e, i) => e.OriginalValues[i]); 
    } 

    private static IEnumerable<Tuple<object, object>> GetRelationships(
     this DbContext context, 
     EntityState relationshipState, 
     Func<ObjectStateEntry, int, object> getValue) 
    { 
     context.ChangeTracker.DetectChanges(); 
     var objectContext = ((IObjectContextAdapter)context).ObjectContext; 

     return objectContext.ObjectStateManager 
          .GetObjectStateEntries(relationshipState) 
          .Where(e => e.IsRelationship) 
          .Select(
            e => Tuple.Create(
              objectContext.GetObjectByKey((EntityKey)getValue(e, 0)), 
              objectContext.GetObjectByKey((EntityKey)getValue(e, 1)))); 
    } 
} 
+0

es versucht, funktioniert nicht. Es beruht darauf, dass die IsRelationship -Eigenschaft wahr ist, aber wie gesagt, zu keinem Zeitpunkt gibt es einen ObjectStateEntry, bei dem IsRelationship auf "true" gesetzt ist ... –

+2

Das funktionierte wie ein Zauber für mich. Es gibt die beiden Enden von Beziehungen zurück, die sich entweder im Status "hinzugefügt" oder "gelöscht" befinden. Sehr nützlich zum Erkennen des Status von Viele-zu-Viele-Beziehungen, die unabhängige Zuordnungen sind (im Gegensatz zu Fremdschlüsselzuordnungen). –