我有一个datagrid,它有一个通过BindingSource绑定到它的集合:
bsProducts.DataSource = cc.Products.Local.ToBindingList();
Grid中的一个实体正在以不同的形式进行编辑(并保存),我想在此表单上刷新网格,现在我尝试重新加载实体,重新加载整个本地上下文但由于某种原因它不是阅读相关的子实体.现在,当我关闭整个表格并再次打开它时,所有内容都被阅读.
要刷新实体,我使用以下代码:
await cc.Entry<Product>(product).ReloadAsync();
但是这不会加载任何绑定到产品实体的相关实体.之后我重新尝试更新BindingSource,但没有运气.
解决方法
我碰巧正在为一个实体对象图的“访问者”工作.看到你的问题,我给了它最后的触摸,使它在你的情况下(和许多其他人)有用.它不是一个真正的访问者,就像众所周知的访问者模式一样,但它基本上做同样的事情:它遍历一个对象图并为它遇到的每个实体执行一些动作.
cc.Visit(product,e => cc.Entry(e).Reload());
…并且您将看到重新加载产品和所有粘附对象.
这是代码:
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,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,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),然后为这些值调用自身.
请注意,我还检查是否已加载导航属性.如果没有这个,可能会触发一连串延迟加载.
另请注意,这会为图中的每个实体触发一个查询.对于大对象图,这不是合适的方法.如果要刷新大量数据,则应采用不同的方法,最好创建新的上下文.