2015-11-24 20 views
7

Ich habe einen Datagrid, die eine Sammlung, um es durch eine Binding gebunden hat:Entity Framework Daten aktualisieren

  bsProducts.DataSource = cc.Products.Local.ToBindingList(); 

Einen der Entitäten in der Grid bearbeitet wird (und gespeichert) in einer anderen Form, und ich würde Ich möchte das Gitter auf diesem Formular aktualisieren, jetzt habe ich versucht, die Entität neu zu laden, lade den gesamten lokalen Kontext neu, aber aus irgendeinem Grund liest es nicht die zugehörigen Unterentitäten. Wenn ich jetzt das ganze Formular schließe und es wieder öffne, wird alles gelesen.

die Entität aktualisieren i den folgenden Code bin mit:

 await cc.Entry<Product>(product).ReloadAsync(); 

Aber das wird keine verbundenen Unternehmen nicht geladen werden, die mit dem Produkt Entity gebunden sind. Ich habe versucht, BindingSource später zu aktualisieren, aber kein Glück.

+0

Nach dem erneuten Laden, binden Sie erneut? – MichaelMao

+0

Ja, aber nach dem ReloadAsync enthält die Eigenschaft immer noch keine verwandten neuen Entitäten, nur die alten. Ich habe eine Umgehung vorgenommen, indem Sie die zugehörigen Entitäten manuell geladen und sie als Liste <> zugeordnet haben. – Martin

+0

versuchen, 'dbProducts.DataBind()' nach dem Update zu verwenden –

Antwort

2

ich zufällig auf einem „Besucher“ für eine Entität Objektgraph zu arbeiten. Als ich deine Frage sah, gab ich ihr die letzte Berührung, um sie in deinem Fall (und vielen anderen) nützlich zu machen. Es ist kein wirklicher Besucher wie im bekannten Besuchermuster, aber es ist im Grunde das Gleiche: Es durchläuft ein Objektdiagramm und führt eine Aktion für jede Entität durch, auf die es trifft.

Mit dieser Methode können Sie einfach ...

cc.Visit(product, e => cc.Entry(e).Reload()); 

... und Sie werden sehen, werden neu geladen anrufen können, dass product und alle anhaftenden Objekte. Hier

ist der Code:

public static class DbContextExtensions 
{ 
    public static void Visit(this DbContext context, object entity, Action<object> action) 
    { 
     Action<object, DbContext, HashSet<object>, Action<object>> visitFunction = null; // Initialize first to enable recursive call. 
     visitFunction = (ent, contxt, hashset, act) => 
      { 
       if (ent != null && !hashset.Contains(ent)) 
       { 
        hashset.Add(ent); 
        act(ent); 
        var entry = contxt.Entry(ent); 
        if (entry != null) 
        { 
         foreach (var np in contxt.GetNavigationProperies(ent.GetType())) 
         { 
          if (np.ToEndMember.RelationshipMultiplicity < RelationshipMultiplicity.Many) 
          { 
           var reference = entry.Reference(np.Name); 
           if (reference.IsLoaded) 
           { 
            visitFunction(reference.CurrentValue, contxt, hashset, action); 
           } 
          } 
          else 
          { 
           var collection = entry.Collection(np.Name); 
           if (collection.IsLoaded) 
           { 
            var sequence = collection.CurrentValue as IEnumerable; 
            if (sequence != null) 
            { 
             foreach (var child in sequence) 
             { 
              visitFunction(child, contxt, hashset, action); 
             } 
            } 
           } 
          } 
         } 
        } 
       } 
      }; 
     visitFunction(entity, context, new HashSet<object>(), action); 
    } 

    // Get navigation properties of an entity type. 
    public static IEnumerable<NavigationProperty> GetNavigationProperies(this DbContext context, Type type) 
    { 
     var oc = ((IObjectContextAdapter)context).ObjectContext; 
     var objectType = ObjectContext.GetObjectType(type); // Works with proxies and original types. 

     var entityType = oc.MetadataWorkspace.GetItems(DataSpace.OSpace).OfType<EntityType>() 
          .FirstOrDefault(et => et.Name == objectType .Name); 
     return entityType != null 
      ? entityType.NavigationProperties 
      : Enumerable.Empty<NavigationProperty>(); 
    } 
} 

Es ist eine rekursive Funktion in einem Verlängerungsverfahren gewickelt. Ich wickelte den rekursiven Teil, so dass ich einen lokalen HashSet in den Graphen senden konnte, der besuchte Entitäten sammelt und dadurch zirkuläre Referenzen verhindert. Grundsätzlich wendet die Funktion die angegebene Aktion auf die Entität an und findet dann ihre Navigationseigenschaften - die Referenzen oder Sammlungen sein können - erhält ihre Werte (CurrentValue) und ruft dann selbst diese Werte auf.

Beachten Sie, dass ich auch überprüfe, ob die Navigationseigenschaften geladen sind. Ohne dies könnte eine endlose Kette von Lazy Loading ausgelöst werden.

Beachten Sie auch, dass dies für jede Entität im Diagramm eine Abfrage auslöst. Dies ist keine geeignete Methode für große Objektdiagramme. Wenn Sie große Datenmengen aktualisieren möchten, sollten Sie einen anderen Ansatz wählen, vorzugsweise einen neuen Kontext erstellen.

2

Haben Sie versucht, die applyCurrentValues ​​() Funktion, es wie Ihr Kontext sieht einfach isin't die neuesten Werte nehmen, wenn Sie bereits eine Refresh-Funktion erstellt, das tut:

bsProducts.DataSource = cc.Products.Local.ToBindingList(); 
bsProducts.DataBind(); 

Dann migth Sie anwenden möchten aktuelle Werte, bevor Sie dies tun.

Sorry, wenn es nicht gelöst wird, ich hatte ein ähnliches Problem und löste es damit, möglicherweise nicht dein Fall.

https://msdn.microsoft.com/en-us/library/dd487246(v=vs.110).aspx

Verwandte Themen