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.
Nach dem erneuten Laden, binden Sie erneut? – MichaelMao
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
versuchen, 'dbProducts.DataBind()' nach dem Update zu verwenden –