我有一个带自引用的实体(由实体设计师生成):
public MyEntity: EntityObject
{
// only relevant stuff here
public int Id { get...; set...; }
public MyEntity Parent { get...; set...; }
public EntityCollection<MyEntity> Children { get...; set...; }
...
}
我编写了一个存储过程,它从表中返回一个节点子树(不只是直接子节点)并返回MyEntity
个对象的列表。我正在使用存储过程来避免任意深树的延迟加载。这样,我就可以在一次调用中从DB中获取相关的子树节点。
List<MyEntity> nodes = context.GetSubtree(rootId).ToList();
一切都很好。但是当我检查nodes[0].Children
时,它的Count
等于0.但是如果我调试并检查context.MyEntities.Results view
,则会填充子枚举。检查我的结果会显示我node[0]
下的孩子。
我如何通过programaticaly强制我的实体上下文来做内存魔术并在Parent
和Children
属性上添加正确的引用?
我试过调用
context.Refresh(ClientWins, nodes);
在GetSubtree()
调用之后,它正确地设置了关系,但是再次从数据库中获取相同的节点。它仍然只是一种解决方法。但比使用context.MyEntities().ToList()
得到整套更好。
我通过使用EF Extensions项目可靠地解决了这个问题。检查下面的答案。
答案 0 :(得分:0)
您需要指定关系的一端。首先,划分集合:
var root = nodes.Where(n => n.Id == rootId).First();
var children = nodes.Where(n => n.Id != rootId);
现在,修复关系。
在您的情况下,您可以:
foreach (var c in children)
{
c.Parent = root;
}
...或:
foreach (var c in children)
{
root.Children.Add(c);
}
哪个没关系。
请注意,这会将实体标记为已修改。如果您打算在上下文中调用SaveChanges
并且不想保存它,则需要更改它。
答案 1 :(得分:0)
基于this article(阅读问题下的文字),当使用存储过程返回数据时,导航属性显然不会被填充/更新。
但是有一个很好的手动解决方案。使用EF Extensions项目并编写您自己的实体Materilizer<EntityType>
,您可以在其中正确设置导航属性,如下所示:
...
ParentReference = {
EntityKey = new EntityKey(
"EntityContextName.ParentEntitySetname",
new[] {
new EntityKeyMember(
"ParentEntityIdPropertyName",
reader.Field<int>("FKNameFromSP")
)
})
}
...
就是这样。调用存储过程将返回正确的数据,并且实体对象实例将彼此正确相关。我建议你查看EF Extensions的样本,在那里你会发现许多不错的东西。