мне довелось работать на «гостя» для объекта объект графа. Увидев ваш вопрос, я дал ему последний штрих, чтобы сделать его полезным в вашем случае (и многих других). Это не настоящий посетитель, как в известном шаблоне посетителя, но он делает в основном одно и то же: он пересекает граф объектов и выполняет какое-то действие для каждой сущности, с которой он сталкивается.
Используя этот метод, вы можете просто позвонить ...
cc.Visit(product, e => cc.Entry(e).Reload());
... и вы увидите, что product
и все прилипшие объекты перезагружается.
Вот код:
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>();
}
}
Это рекурсивная функция, завернутые в метод расширения. Я завернул рекурсивную часть, чтобы я мог отправить локальный HashSet
по графику, который собирает посещенные объекты и тем самым предотвращает циклические ссылки. В основном функция применяет указанное действие к сущности, а затем находит, что ее свойства навигации, которые могут быть ссылками или наборами, получают свои значения (CurrentValue
), а затем называет себя для этих значений.
Обратите внимание, что я также проверяю, загружены ли свойства навигации. Без этого может начаться бесконечная цепочка ленивой загрузки.
Также обратите внимание, что это вызывает один запрос для каждого объекта на графике. Это не подходит для графов больших объектов. Если вы хотите обновить большие объемы данных, вы должны использовать другой подход, предпочтительно создать новый контекст.
После перезагрузки вы снова связываетесь? – MichaelMao
Да, но после ReloadAsync свойство по-прежнему не содержит никаких связанных с ним связанных объектов, а только старых. Я сделал обходной путь, вручную загрузив связанные объекты и назначив их как List <>. – Martin
попытайтесь использовать 'dbProducts.DataBind()' после обновления –