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.
Po ponownym załadowaniu, czy wiążesz ponownie? – MichaelMao
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
spróbuj użyć 'dbProducts.DataBind()' po aktualizacji –