2016-03-31 8 views
0

Gibt es eine Möglichkeit, den aktuellen Wert einer Entity-Eigenschaft in BeforeSaveEntity (oder anderswo vor dem Speichern) auf der Serverseite zu erhalten ? Mit "aktuell" meine ich, was in der Datenbank vorhanden ist, wobei alle eingehenden Änderungen zusammengeführt werden. Dies ist nicht zur Validierung gedacht, sondern ich berechne einen Wert für eine Elterneigenschaft (die ich nicht auf dem Client haben möchte) basierend auf beiden Eltern Felder und Kinder Felder ...breeze - Ändern einer Entität auf dem Server basierend auf den Navigationseigenschaften vor dem Speichern

Zum Beispiel

public class Parent { 
    public ICollection<Child> Children{ get; set; } 
} 

. . .

protected override bool BeforeSaveEntity(EntityInfo entityInfo) { 
    if (entityInfo.Entity.GetType() == typeof(Parent) && 
    (entityInfo.EntityState == EntityState.Added || entityInfo.EntityState == EntityState.Updated)) { 

    // Lazy load Parent's Children collection out of breeze's context 
    // so items are "current' (existing merged with changes) 

    Parent parent = (Parent)entityInfo.Entity; 
    Context.Entry(parent).Collection(p => p.Children).Load(); 

    // this throws exception Member 'Load' cannot be called for property 
    // 'Children' because the entity of type 'Parent' does not exist in the context. 
    } 
} 

Ich denke, sie sind nicht im DBContext noch. Alles, was ich tun kann, ist, die vorhandenen Kinder aus der Datenbank abzurufen und die Änderungen in BeforeSaveEntities manuell zusammenzuführen, was mühsam ist.

Antwort

1

Lazy Loading ist im DbContext nicht aktiviert, den Breeze zum Speichern verwendet. Der Grund ist detailliert in this SO answer.

Sie sollten zusätzliche Entitäten in eine separate DbContext laden.


Hier ist ein Beispiel, wie ich es in einem Projekt gemacht habe. Vielleicht sollten die Methoden MergeEntities und DetachEntities in Breeze enthalten sein, um das zu vereinfachen.

protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) 
{ 
    // create a separate context for computation, so we don't pollute the main saving context 
    using (var newContext = new MyDbContext(EntityConnection, false)) 
    { 
     var parentFromClient = (Parent)saveMap[typeof(Parent)][0].Entity; 

     // Load the necessary data into the newContext 
     var parentFromDb = newContext.Parents.Where(p => p.ParentId == parentFromClient.ParentId) 
      .Include("Children").ToList(); 

     // ... load whatever else you need... 

     // Attach the client entities to the ObjectContext, which merges them and reconnects the navigation properties 
     var objectContext = ((IObjectContextAdapter)newContext).ObjectContext; 
     var objectStateEntries = MergeEntities(objectContext, saveMap); 

     // ... perform your business logic... 

     // Remove the entities from the second context, so they can be saved in the original context 
     DetachEntities(objectContext, saveMap); 
    } 
    return saveMap; 
} 

/// Attach the client entities to the ObjectContext, which merges them and reconnects the navigation properties 
Dictionary<ObjectStateEntry, EntityInfo> MergeEntities(ObjectContext oc, Dictionary<Type, List<EntityInfo>> saveMap) 
{ 
    var oseEntityInfo = new Dictionary<ObjectStateEntry, EntityInfo>(); 
    foreach (var type in saveMap.Keys) 
    { 
     var entitySet = this.GetEntitySetName(type); 
     foreach(var entityInfo in saveMap[type]) 
     { 
      var entityKey = oc.CreateEntityKey(entitySet, entityInfo.Entity); 
      ObjectStateEntry ose; 
      if (oc.ObjectStateManager.TryGetObjectStateEntry(entityKey, out ose)) 
      { 
       if (ose.State != System.Data.Entity.EntityState.Deleted) 
        ose.ApplyCurrentValues(entityInfo.Entity); 
      } 
      else 
      { 
       oc.AttachTo(entitySet, entityInfo.Entity); 
       ose = oc.ObjectStateManager.GetObjectStateEntry(entityKey); 
      } 

      if (entityInfo.EntityState == Breeze.ContextProvider.EntityState.Deleted) 
      { 
       ose.Delete(); 
      } 
      oseEntityInfo.Add(ose, entityInfo); 
     } 
    } 
    return oseEntityInfo; 
} 

/// Remove the entities in saveMap from the ObjectContext; this separates their navigation properties 
static void DetachEntities(ObjectContext oc, Dictionary<Type, List<EntityInfo>> saveMap) 
{ 
    foreach (var type in saveMap.Keys) 
    { 
     foreach (var entityInfo in saveMap[type]) 
     { 
      try 
      { 
       oc.Detach(entityInfo.Entity); 
      } 
      catch 
      { // the object cannot be detached because it is not attached 
      } 
     } 
    } 
} 
+0

Ich sah diese Antwort, aber ich brauche den aktuellen Zustand der Navigation mit allen eingehenden Änderungen. Also muss ich die Savemap durchlaufen und irgendwelche "Kinder" Änderungen für meine "Eltern" zusammenführen? – user210757

+0

Wie würden Sie mit einer Sicherung umgehen, die Sie über den Eingangszustand einer Entität und der damit verbundenen Entitäten wissen müssen? – user210757

+0

Ich habe meiner Antwort ein langes Beispiel hinzugefügt. Hoffe das hilft. –