在实体框架4.1中同步反向关联的指导4.1 [英] Guidance for synchronising reverse associations in Entity Framework 4.1
问题描述
我反对关联同步的意思是:
public class Blog
{
public Blog(){Posts = new List< Blog>(); }
public int Id {get;组; }
public ICollection< Post>帖子{get;私人集合
}
public class Post
{
public Blog Blog {get;组; }
public int Id {get;组; }
}
然后在以下行后,Post将其Blog属性设置为
var blog = new Blog();
context.Blogs.Add(blog);
blog.Posts.Add(new Post());
我相信 - 但我不知道 - 同步反向关联是指实体框架中的一个功能,称为关系修正或关系跨度,并且负责在ObjectContext中的对象之间自动分配导航属性。这不是特定于EF 4.1,但也适用于较旧的版本。
我不知道此功能的全面文档,但这里有一些资源可能会给出更多的洞察力 - 特别是第二个:
-
一个简短的定义: http://blogs.msdn.com/b/alexj/档案/ 2009/04/03 / tip-10-understanding-entity-framework-jargon.aspx
-
更详细的解释(Zeeshan Hirani ): http://www.daltinkurt.com/upload/dosyalar/文件/ Diger / entity_framework_learning_guide.pdf (第115页 - 第133页)
-
关于希望避免关系跨度的情况: http://blogs.msdn.com/b/alexj/archive/2009/04/07/tip-11-avoiding-relationship-span.aspx
修改
我无法全面解释关系跨度及其影响。但是我可以尝试给出一些例子,我感到安全,这并不完全是错误的:
在答案您在评论中已链接 Morteza在派生自 EntityObject $在EF 4.0中,c $ c>(只有
ObjectContext
,不可能在EF 4.1中使用 DbContext
)和POCO(可能与 ObjectContext
和 DbContext
)。
如果您有POCO然后将新对象添加到已经加载到上下文中的另一个对象的导航集合中,将将新对象附加到上下文中。这并不奇怪,因为POCO是...,POCO,这意味着他们不了解EF环境。将一个对象添加到导航集合中,实际上并不仅仅是像 List< T> .Add(...)
。这个通用的添加
方法在EF上下文中不执行任何操作。
这是另一种情况, EntityObject
和 EntityCollection
,它们都内部引用了上下文,因此可以在添加到集合中时立即附加到上下文中。
从这个考虑的一个结论是,你的问题的最后一个代码示例将不实际设置 Blog <当您使用POCO时,code> Post
中的code>属性。但是,您调用 DetectChanges
或 SaveChanges
(调用 DetectChanges
内部)。在这种情况下, DetectChanges
(这可能是一个非常复杂的方法)查看上下文中有什么对象(它会找到 Blog
父对象),然后遍历整个对象图(在我们的例子中为 Posts
collection),并检查图中的其他对象( Post
objects)也在上下文中。如果没有 - 在你的例子中就是这种情况 - 它会将它们附加到中的上下文中添加
状态和 - 这里将关系跨度现在 - 还可以修正对象图形中的导航属性。
另外,关系跨度也与POCO相关联的情况是将对象加载到上下文中时。
例如:如果您有一个博客
,其中id = x和 Post
id = y,属于这个博客
在数据库中,然后这个代码...
var blog = context.Blogs.Find(x); //不需要加载帖子收藏!
var post = context.Posts.Find(y); //不需要加载Blog属性!
将自动构建每个对象的导航属性,因此 / code>
的集合将突然包含
博客
属性在 Post
将引用博客。这种关系修复取决于事物确实加载到上下文中。如果您通过使用 AsNoTracking
来抑制此情况,例如...
var blog = context.Blogs.AsNoTracking()。Where(b => b.Id == x).Single();
var post = context.Posts.AsNoTracking()。其中(p => p.Id == y).Single();
...关系跨度不起作用,导航属性将保持 null
。
最后一个注释:关系跨度 - 如上例所示 - 仅在至少一端的关联具有基数的 0 ... 1
(一对一或一对多关联)。它从来不适用于多对多协会。这是最近在这里讨论的(与EF 4.1): EF 4.1加载过滤的子集合不适用于多对多
EF 4.1 synchronises reverse associations when you create your instances. Is there any documentation of or best practices guidance available for this behaviour?
What I mean by synchronising the reverse association is that given:
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; }
}
Then after the following line the Post will have it's Blog property set.
var blog = new Blog();
context.Blogs.Add(blog);
blog.Posts.Add(new Post());
I believe - but I'm not sure - with "synchronising the reverse association" you mean a feature in Entity Framework which is called Relationship Fix-up or Relationship Span and is responsible to assign automatically navigation properties between objects in the ObjectContext. This is not specific to EF 4.1 but exists also for older versions.
I don't know a comprehensive documentation for this feature but here are a few resources which may give a bit more insight - especially the second one:
A brief definition: http://blogs.msdn.com/b/alexj/archive/2009/04/03/tip-10-understanding-entity-framework-jargon.aspx
A more detailed explanation (Zeeshan Hirani): http://www.daltinkurt.com/upload/dosyalar/file/Diger/entity_framework_learning_guide.pdf (Chapter 3.4 at page 125 - 133)
About situations where one wants to avoid relationship span: http://blogs.msdn.com/b/alexj/archive/2009/04/07/tip-11-avoiding-relationship-span.aspx
Edit
I am not able to give a comprehensive explanation of relationship span and all its impacts. But I can try to give a few examples where I feel safe that it's not completely wrong what I say:
In the answer you have linked in the comment Morteza makes a difference between entities which are derived from EntityObject
(only ObjectContext
in EF 4.0, not possible with DbContext
in EF 4.1) and POCOs (possible with ObjectContext
and DbContext
).
If you have POCOs then adding a new object to a navigation collection of another object which is already loaded into the context would not attach the new object to the context. This is not surprising because POCOs are, well..., POCOs, which means that they don't know anything about the EF context. Adding an object to a navigation collection is really nothing more than something like List<T>.Add(...)
. This generic Add
method doesn't do any operation on the EF context.
This is another situation with EntityObject
and EntityCollection
which both have references to the context internally and can therefore attach to the context immediately when you add to the collection.
One conclusion from this consideration is that the last code example in your question would not actually set the Blog
property in the Post
when you use POCOs. But: It will be set after you have called DetectChanges
or SaveChanges
(which calls DetectChanges
internally). In this situation DetectChanges
(which is probably a very complex method) looks into context what objects are there (it'll find the Blog
parent object) and then runs through the whole object graph (the Posts
collection in our case) and checks if the other objects in the graph (the Post
objects) are also in the context. If not - and this is the case in your example - it will attach them to the context in Added
state and - here comes relationship span into play now - also fix the navigation properties in the object graph.
Another situation where relationship span also acts with POCOs is when you load objects into the context.
For example: If you have a Blog
with id = x and a Post
with id = y which belongs to this Blog
in the database then this code ...
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!
would automatically build up the navigation properties in each object, so the Posts
collection of the Blog
will suddenly contain the post and the Blog
property in Post
will refer to the blog. This relationship fix-up depends on the fact that the objects are indeed loaded into the context. If you suppress this by using AsNoTracking
for example ...
var blog = context.Blogs.AsNoTracking().Where(b => b.Id == x).Single();
var post = context.Posts.AsNoTracking().Where(p => p.Id == y).Single();
... relationship span doesn't work and the navigation properties will stay null
.
A last note: Relationship span - as in the example above - only works if the assocation on at least one end has a cardinality of 0...1
(one-to-one or one-to-many associations). It never works for many-to-many associations. This was recently discussed here (with EF 4.1): EF 4.1 loading filtered child collections not working for many-to-many
这篇关于在实体框架4.1中同步反向关联的指导4.1的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!