【问题标题】:Guidance for synchronising reverse associations in Entity Framework 4.1在 Entity Framework 4.1 中同步反向关联的指南
【发布时间】:2011-09-09 06:19:29
【问题描述】:

EF 4.1 在您创建实例时同步反向关联。是否有任何关于此行为的文档或最佳实践指南?

我所说的同步反向关联的意思是:

public class Blog
{
   public Blog() { Posts = new List<Blog>(); }
   public int Id { get; set; }
   public ICollection<Post> Posts { get; private set; }
}

public class Post
{
   public Blog Blog { get; set; }
   public int Id { get; set; }
}

然后在以下行之后,帖子将设置它的博客属性。

var blog = new Blog();
context.Blogs.Add(blog);
blog.Posts.Add(new Post());

【问题讨论】:

    标签: entity-framework-4.1 ef-code-first


    【解决方案1】:

    我相信 - 但我不确定 - “同步反向关联”是指实体框架中的一个功能,称为 Relationship Fix-upRelationship Span 并负责在 ObjectContext 中的对象之间自动分配导航属性。这并非特定于 EF 4.1,但也适用于旧版本。

    我不知道有关此功能的全面文档,但这里有一些资源可能会提供更多见解 - 尤其是第二个:

    编辑

    我无法全面解释关系跨度及其所有影响。但我可以试着举几个例子,让我觉得我所说的并不是完全错误的:

    answer you have linked in the comment 中,Morteza 对派生自EntityObject 的实体(仅在EF 4.0 中ObjectContext,在EF 4.1 中不适用于DbContext)和POCO(可能与ObjectContext 和@ 987654331@).

    如果您有 POCO,则将新对象添加到已加载到上下文中的另一个对象的导航集合中,不会将新对象附加到上下文中。这并不奇怪,因为 POCO 是……好吧,POCO,这意味着他们对 EF 上下文一无所知。将对象添加到导航集合实际上只不过是List&lt;T&gt;.Add(...) 之类的东西。这个通用的 Add 方法不对 EF 上下文执行任何操作。

    这是EntityObjectEntityCollection 的另一种情况,它们都在内部引用了上下文,因此可以在您添加到集合时立即附加到上下文。

    从这一考虑得出的一个结论是,当您使用 POCO 时,您问题中的最后一个代码示例不会实际上在 Post 中设置 Blog 属性。但是:它在您调用DetectChangesSaveChanges(在内部调用DetectChanges)之后设置。在这种情况下,DetectChanges(这可能是一个非常复杂的方法)查看上下文中有哪些对象(它会找到 Blog 父对象),然后遍历整个对象图(我们的 Posts 集合case) 并检查图中的其他对象(Post 对象)是否也在上下文中。如果不是 - 在您的示例中就是这种情况 - 它会将它们附加到 Added 状态的上下文中 - 现在 relationship span 开始发挥作用 - 还修复对象图中的导航属性.

    关系跨度也对 POCO 起作用的另一种情况是当您将对象加载到上下文中时。

    例如:如果您有一个 id = x 的 Blog 和一个 id = y 的 Post 属于数据库中的这个 Blog 那么这个代码......

    var blog = context.Blogs.Find(x); // no eager loading of the Posts collection!
    var post = context.Posts.Find(y); // no eager loading of the Blog property!
    

    会自动在每个对象中建立导航属性,因此BlogPosts 集合将突然包含帖子,Post 中的Blog 属性将引用博客。这种关系修复取决于对象确实加载到上下文中的事实。如果您使用 AsNoTracking 来抑制这种情况,例如 ...

    var blog = context.Blogs.AsNoTracking().Where(b => b.Id == x).Single();
    var post = context.Posts.AsNoTracking().Where(p => p.Id == y).Single();
    

    ...关系跨度不起作用,导航属性将保持null

    最后一点:关系跨度 - 如上例所示 - 仅在至少一端的关联具有0...1 的基数(一对一或一对多关联)时才有效。它从不适用于多对多关联。最近在这里讨论了这一点(使用 EF 4.1):EF 4.1 loading filtered child collections not working for many-to-many

    【讨论】:

    • 谢谢 Slauma,我之前没听说过关系跨度这个词。这有助于找到有关这种行为的材料。在阅读了您的链接并搜索了其他信息后,我发现了这个 SO 答案:goo.gl/4j888。 Morteza 似乎在说,Relationship Span 在代码优先中的工作方式不同。不确定...
    • @Sean Kearon:现在我的回答中有一个编辑。 (我只想写一个简短的评论,但它越来越长了。)
    • Slauma,感谢您回来并提供有关行为的如此全面的答案。
    猜你喜欢
    • 2011-11-03
    • 2012-10-20
    • 2011-08-26
    • 2014-09-05
    • 1970-01-01
    • 2011-09-10
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    相关资源
    最近更新 更多