Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attach same object to different contexts in Entity Framework 6

From everything I read until now it should not be possible to attach same object to different dbcontexts (and all the examples and questions I could find were showing exceptions in such cases). Right now as I tested with EF6 it allowed me to attache the same object to different contexts (from different threads); I was even able to change teh object from one thread and save it with the other thread. This is not necessarily a bad thing (except the fact I must make sure I lock all the time as there is no exception thrown), just that I would like to understand what is going on.

Does anybody know if this is really a "new feature" in EF6?

Some code here. Calling this from several different threads gave no exception, and if I change the object from another thread before save it takes the last values:

                        using (var db = new TestContext())
                        {
                            db.Users.Attach(_cachedUser);
                            MessageBox.Show("attached"); //I use this to pause the thread as long as I want
                            _cachedUser.UserCode = tbCode.Text;
                            _cachedUser.UserDesc = tbDesc.Text;
                            MessageBox.Show("ready to save"); //pause again
                            db.SaveChanges();
                        }

Edit After receiving the answer why this happens, I also found how to check if an object is proxy or not: http://msdn.microsoft.com/en-us/library/vstudio/ee835846(v=vs.100).aspx

public static bool IsProxy(object type)
{
    return type != null && ObjectContext.GetObjectType(type.GetType()) != type.GetType();
}

Works just fine.

like image 861
user3346850 Avatar asked Mar 18 '14 13:03

user3346850


1 Answers

This has been possible since Entity Framework introduced the code-first style, because you can only do this with POCOs.

The cachedUser is a plain C# class. It has no information whatsoever about a context it's attached to. Also, a new context instance has not knowledge whatsoever of another context's change tracker. So there is no way to check if a POCO is attached to a context anywhere.

This changes when cachedUser is not a POCO, but a proxy object. (A proxy object is an object that EF creates on the fly. It inherits from the entity class and it contains code and state that enables lazy loading and facilitates change tracking). When you try to attach a proxy object to a second context you'll get an exception:

An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

That's why for many scenarios it's recommended to create proxies instead of POCOs. You can create proxies by using db.Users.Create() in stead of new User().

When to create proxies, whether this is possible at all and when EF materialized proxies is a subject that's beyond the scope of this question. More about this can be found here.

like image 176
Gert Arnold Avatar answered Oct 20 '22 15:10

Gert Arnold