2015-11-24 10 views
7

Mam datagrid, który posiada kolekcję związaną z nim za pośrednictwem BindingSource:Entity Framework odświeżania danych

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

jeden z podmiotów w siatce jest edytowany (i zapisane) w innej formie i ja jak odświeżyć siatkę w tym formularzu, teraz próbowałem przeładować encję, przeładowałem cały lokalny kontekst, ale z jakiegoś powodu nie czytałem powiązanych podsieci. Teraz, kiedy zamykam cały formularz i ponownie go otwieram, wszystko jest czytane.

Aby odświeżyć podmiot używam następujący kod:

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

Ale to nie będzie ładować jakiekolwiek podmioty powiązane, które są związane z jednostkowego produktu. Ponownie próbowałem zaktualizować BindingSource, ale bez powodzenia.

+0

Po ponownym załadowaniu, czy wiążesz ponownie? – MichaelMao

+0

Tak, ale po funkcji ReloadAsync właściwość nadal nie zawiera żadnych powiązanych z nią powiązanych obiektów, tylko te stare. Dokonałem obejścia, ręcznie ładując powiązane obiekty i przypisując je do listy <>. – Martin

+0

spróbuj użyć 'dbProducts.DataBind()' po aktualizacji –

Odpowiedz

2

zdarzyło mi się pracować na „gościa” na wykresie obiektu podmiot. Widząc twoje pytanie, nadałem mu ostatni szlif, aby był przydatny w twoim przypadku (i wielu innych). Nie jest prawdziwym gościem, jak w dobrze znanym modelu odwiedzającego, ale w zasadzie to samo: przechodzi przez wykres obiektów i wykonuje jakąś akcję dla każdej napotkanej istoty.

Stosując tę ​​metodę można po prostu zadzwonić ...

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

... a zobaczysz, że product i wszystkie przylegające obiekty są przeładowane.

Oto kod:

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

Jest to funkcja rekurencyjna zawinięte w metodę rozszerzenia. Zawinęłem część rekursywną, dzięki czemu mogłem wysłać lokalny HashSet w dół wykresu, który zbiera odwiedzane obiekty, a tym samym zapobiega odwołaniom cyklicznym. Zasadniczo funkcja stosuje określone działanie do obiektu, a następnie jego właściwości nawigacyjne - które mogą być odniesieniami lub kolekcjami - pobierają ich wartości (CurrentValue), a następnie wywołuje się dla tych wartości.

Zauważ, że sprawdzam również, czy załadowane są właściwości nawigacji. Bez tego może zostać uruchomiony nieskończony łańcuch leniwego ładowania.

Należy również zauważyć, że powoduje to uruchomienie jednego zapytania dla każdej jednostki na wykresie. Nie jest to odpowiednia metoda dla wykresów dużych obiektów. Jeśli chcesz odświeżyć duże ilości danych, powinieneś przyjąć inne podejście, najlepiej stworzyć nowy kontekst.

2

Czy próbował ApplyCurrentValues ​​() funkcja, wygląda context tylko isin't biorąc najnowsze wartości, jeśli już stworzyliśmy funkcję odświeżania, które wykonuje:

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

Następnie migth chcesz zastosować bieżące wartości przed wykonaniem tego.

Przepraszam, jeśli to nie rozwiąże problemu, miałem podobny problem i rozwiązałem go, może nie być twoim przypadkiem.

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