Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
342 views
in Technique[技术] by (71.8m points)

ef code first - Guidance for synchronising reverse associations in Entity Framework 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());
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...