我认为你所说的“synchronising the reverse association”可能是Entity Framework中称为“Relationship Fix-up”或“Relationship Span”的功能,它负责在ObjectContext中自动分配对象之间的导航属性。这不仅适用于EF 4.1,也适用于旧版本。
我不知道这个功能的全面文档,但以下资源可能会提供更多见解,特别是第二个:
- 简要定义:
http://blogs.msdn.com/b/alexj/archive/2009/04/03/tip-10-understanding-entity-framework-jargon.aspx
- 更详细的解释(Zeeshan Hirani):
http://www.daltinkurt.com/upload/dosyalar/file/Diger/entity_framework_learning_guide.pdf(第3.4章,第125-133页)
- 关于想避免关系跨度的情况:
http://blogs.msdn.com/b/alexj/archive/2009/04/07/tip-11-avoiding-relationship-span.aspx
编辑:
我无法给出关于关系跨度及其所有影响的全面解释。但我可以尝试给出一些例子,我相信我的说法不是完全错误的:
在你评论中链接的
答案中,Morteza区分了派生自EntityObject的实体(仅适用于EF 4.0中的ObjectContext,在EF 4.1中的DbContext不可用)和POCOs(在ObjectContext和DbContext中均可用)。
如果您有POCOs,则将新对象添加到已加载到上下文中的另一个对象的导航集合中不会将新对象附加到上下文中。这并不奇怪,因为POCOs是POCOs,这意味着它们对EF上下文一无所知。将对象添加到导航集合中实际上只是类似于List<T>.Add(...)这样的操作。这个通用的Add方法不会对EF上下文进行任何操作。
这是涉及到EntityObject
和EntityCollection
的另一种情况,它们都在内部引用了上下文,并且因此当您将其添加到集合时可以立即附加到上下文。
从这个考虑中得出的一个结论是,在使用POCO时,您的问题中的最后一个代码示例实际上不会设置Post
中的Blog
属性。但是:在调用DetectChanges
或SaveChanges
(它在内部调用DetectChanges
)之后,它将被设置。在这种情况下,DetectChanges
(可能是一个非常复杂的方法)查看上下文中有哪些对象(它会找到Blog
父对象),然后遍历整个对象图(在我们的例子中是Posts
集合),并检查图中的其他对象(Post
对象)是否也在上下文中。如果没有 - 这就是您的例子中的情况 - 它将以Added
状态将它们附加到上下文中,并且现在出现了关系跨度 - 也会修复对象图中的导航属性。
关系跨度还在加载对象到上下文时与POCO一起使用的另一种情况。
例如:如果您在数据库中有一个id = x的Blog
和一个属于此Blog
的id = y的Post
,则此代码...
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!
会自动在每个对象中建立导航属性,因此
Blog 的 Posts 集合将突然包含帖子,并且 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();
注意:如果关联的至少一端的基数为0...1
(一对一或一对多关联),则像上面的示例中那样的关系跨度才有效。对于多对多关联,它永远不起作用。最近在这里讨论过这个问题(使用EF 4.1):EF 4.1 loading filtered child collections not working for many-to-many
另外一点:关系跨度无法工作,并且导航属性将保持null
。