0

我有一个带有自引用的实体(由实体设计器生成):

public MyEntity: EntityObject
{
    // only relevant stuff here
    public int Id { get...; set...; }
    public MyEntity Parent { get...; set...; }
    public EntityCollection<MyEntity> Children { get...; set...; }
    ...
}

我编写了一个存储过程,它从表中返回节点的子树(不仅仅是直接子节点)并返回MyEntity对象列表。我正在使用存储过程来避免延迟加载任意深度树。这样,我可以在一次调用中从数据库中获取相关的子树节点。

List<MyEntity> nodes = context.GetSubtree(rootId).ToList();

一切都好。但是当我检查时nodes[0].Children,它Count等于 0。但是如果我调试和检查context.MyEntities.Results view,儿童枚举会被填充。检查我的结果显示我的孩子node[0]

如何以编程方式强制我的实体上下文执行内存魔术并在属性上放置正确的Parent引用Children

更新 1

我试过打电话

context.Refresh(ClientWins, nodes);

在我的GetSubtree()电话确实正确设置了关系之后,但再次从数据库中获取了相同的节点。它仍然只是一种解决方法。但总比用context.MyEntities().ToList().

更新 2

我已经通过使用 EF Extensions 项目可靠地解决了这个问题。在下面检查我的答案。

4

2 回答 2

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上下文并且不希望保存它,则需要更改它。

于 2009-12-11T14:10:38.990 回答
0

真正的解决方案

根据这篇文章(阅读问题下的文本),当使用存储过程返回数据时,导航属性显然不会被填充/更新。

但是有一个很好的手动解决方案。使用EF Extensions项目并编写您自己的实体Materilizer<EntityType>,您可以在其中正确设置导航属性,如下所示:

...
ParentReference = {
    EntityKey = new EntityKey(
        "EntityContextName.ParentEntitySetname",
        new[] {
            new EntityKeyMember(
                "ParentEntityIdPropertyName",
                reader.Field<int>("FKNameFromSP")
            )
        })
}
...

就是这样。调用存储过程将返回正确的数据,实体对象实例将正确地相互关联。我建议您查看 EF Extensions 的示例,在那里您会发现很多好东西。

于 2009-12-14T11:44:33.647 回答