Attach same object to different contexts in Entity Framework 6 - c#

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.

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.

Related

Determine if the context of an entity proxy has been disposed

In a EF 6 project, I am writing validation functions for entities. some are static while others are instance methods of the entities themselves.
Ignoring whether this is bad practice or not, I'd like to check whether the entities were created using a context and if so, whether they are still attached.
Please note that these functions do NOT have access to the context object, just the entity classes.
As an example, a method validates Department entity and cascades validation to all associated Department.Employee instances.
If the hierarchy was created manually, validation will succeed.
If the hierarchy was created using a context which is still alive, validation will succeed albeit slower.
If the hierarchy was created using a context which has been disposed, validation will fail with an ObjectDisposedException (provided proxy-creation was enabled and .Include(***) was not used).
So the question, is it possible to detect the above scenarios without access to a DbContext instance? If not, how can we best validate entire hierarchies irrespective of how they were created.
var result = true;
var departments = ???; // Constructed manually or through a DbContext instance.
foreach (var department in departments)
{
result &= department.Validate();
foreach (var employee in department.Employees)
{
result &= employee.Validate();
}
}
EDIT: Please note that this is for a desktop application that cannot have long-running DbContext instances. they are almost always disposed immediately after retrieving data. Re-querying the database does not seem a viable option for validation since it is triggered by trivial user input and would slow down the entire user experience.
From your question
Please note that these functions do NOT have access to the context object, just the entity classes.
two solutions come to mind, none really palatable:
Build your own tracker and make it available to these methods somehow.
Add something to your entities, for example a WasLoaded property that gets set when you query your context. That WasLoaded could be set by either
Writing an EF interceptor that sets it.
Adding an artificial bit column with all values set to 1. Then map that to the property; the property will be false if you constructed it outside of the context, true if loaded from the context.
The tracker seems to be the cleanest because it doesn't pollute your model. The interceptor is a decent alternative if you're not concerned about your model.
And while it doesn't answer your question directly, you could avoid the use of proxies, in which case your validation works the same way regardless because you have your model in memory. There's the usual trade-offs to consider though.
I'm not sure how you'd detect the last scenario. I suppose you could have your tracker track more than the entities... have it also track the context's state.

How to update object with lazy properties (proxy object) in another session?

I attempted to get the object that has lazy properties in a session and tried to update it in another session. But it failed to do so
with an Error: No persister for SecUserProxy (actual class is SecUser)
I'm using NHibernate 3.4. When I googled I came to know its a bug which has been fixed.
I also came across this post in which it is said if your proxy object implements INhibernateProxy, you can unproxy the object
with NHibernate. As NHibernate no longer supports pluggable proxy factories (like Castle, LinFu etc), it uses an internal one, I'm
assuming the internal one is perhaps INhibernateProxy
So I did the following in New session where I want to update my object as:
object unprox_obj = Session
.GetSessionImplementation()
.PersistenceContext.Unproxy(secUserobj);
in anticipation of getting this same object but with the real type i-e SecUser so that it can update without any error. But it still returns a proxy object.
I'm not able to understand what is going on?
Updated:
I have realized just now that 'secUserobj' is not INhibernateProxy. So How can I make it INhibernateProxy in order to update my object within another session?
if (secUserobj is INHibernateProxy)
{
unprox_obj = Session
.GetSessionImplementation()
.PersistenceContext.Unproxy(secUserobj);
}
Detached objects (loaded in one session, and kept as reference) could be re-attached. We can use session.Merge() or session.Lock()
9.4.2. Updating detached objects
Many applications need to retrieve an object in one transaction, send it to the UI layer for manipulation, then save the changes in a new transaction....
...
...The last case can be avoided by using Merge(Object o). This method copies the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. The method returns the persistent instance. If the given instance is unsaved or does not exist in the database, NHibernate will save it and return it as a newly persistent instance. Otherwise, the given instance does not become associated with the session. In most applications with detached objects, you need both methods, SaveOrUpdate() and Merge().
19.1.4. Initializing collections and proxies
...
You may also attach a previously loaded object to a new ISession with Merge() or Lock() before accessing uninitialized collections (or other proxies). No, NHibernate does not, and certainly should not do this automatically, since it would introduce ad hoc transaction semantics!
...
So, we can pass detached reference into .Merge(), and later work with returned (brand new) object reference:
MyEntity reAttached = session.Merge<MyEntity>(detached);
Be careful, this should be done (as stated above) before any of the detached collections were touched.

How to determine which connection string/context from an unknown Entity Framework model?

Pardon my question if this has been asked before but I'm not 100% sure if my google wording is not accurate or if this just isn't a normal thing.
I have a WCF service where I need to pass in any type of Entity Framework model object (unknown by virtue of the fact that I need to treat these objects nearly identically without writing a new interface contract for each model because they all save the same way, for example).
So far, this is great. They're passed in, I seem to be getting the type just fine (I think so far) so I can treat them "generically."
My new conundrum is: How do I get the reference to the database connection string from the entity object?
Is there a way to say something similar to (pardon some of the extreme psuedo here):
object DbContext = genericEFObject.databaseEntityConnection; //need help here
typeof(DBContext) db = typeof(DBContext); //possibly help here too
db.Entry(genericEFObject).State = System.Data.Entity.EntityState.Added;
db.SaveChanges();
I'd like to avoid passing in the db object to the contract, if possible.
Any awesomeness to be had here?
I'm sorry to say that there's not any remotely easy way to do this. You'll have to write a lot of code and abuse Reflection like it's going out of style. These are your options as far as I can see:
Generic method
The DbContext is not getting serialized and passed over WCF. So that will leave you with either a POCO Entity object to create, update or delete or a nice long expression tree representing a query. You then have to figure out what DbContext it belongs to, instantiate said DbContext, figure out what DbSet it belongs to, and use it on the DbSet all via reflection.
Code generation
You will still need a lot of reflection to pull out all the DbContexts and DbSets but once you have those, generating methods for all of them should be a breeze. You'll have a lot more flexibility as to what conventions you can apply to different operations. The downside is that there will be a lot of code there and it might get a little hard to manage unless you find some way to break it up into different namespaces.
Normally, the answer is NO - it is not possible to get context instance from an entity object without doing some reflection things. This is generally considered a bad practice to have entities that are aware of the storage they were produced from.
However, because of the way Entity Framework is implemented right now (v6.1.1), technically there is a way to achieve this in a 'hacking manner' when your context configured to create proxies (ProxyCreationEnabled = true).
Here's a very bad code that will give you an ObjectContext from an entity object (warning: do not even consider to use this in production):
var ctx = new MyContext();
ctx.Configuration.ProxyCreationEnabled = true;
dynamic dynamicEntity = ctx.Employees.First();
var entityWrapper = dynamicEntity._entityWrapper;
Type type = entityWrapper.GetType();
var contextProperty = type.GetProperty("Context");
var objectContext = contextProperty.GetValue(entityWrapper) as ObjectContext;

Entity Framework Multiple Object Contexts

This question has been asked 500 different times in 50 different ways...but here it is again, since I can't seem to find the answer I'm looking for:
I am using EF4 with POCO proxies.
A.
I have a graph of objects I fetched from one instance of an ObjectContext. That ObjectContext is disposed.
B.
I have an object I fetched from another instance of an ObjectContext. That ObjectContext has also been disposed.
I want to set a related property on a bunch of things from A using the entity in B....something like
foreach(var itemFromA in collectionFromA)
{
itemFromA.RelatedProperty = itemFromB;
}
When I do that, I get the exception:
System.InvalidOperationException occurred
Message=The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
Source=System.Data.Entity
StackTrace:
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedEntity, Boolean applyConstraints)
at System.Data.Objects.DataClasses.EntityReference`1.set_ReferenceValue(IEntityWrapper value)
at System.Data.Objects.DataClasses.EntityReference`1.set_Value(TEntity value)
at
I guess I need to detach these entities from the ObjectContexts when they dispose in order for the above to work... The problem is, detaching all entities from my ObjectContext when it disposes seems to destroy the graph. If I do something like:
objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged)
.Select(i => i.Entity).OfType<IEntityWithChangeTracker>().ToList()
.ForEach(i => objectContext.Detach(i));
All the relations in the graph seem to get unset.
How can I go about solving this problem?
#Danny Varod is right. You should use one ObjectContext for the whole workflow. Moreover because your workflow seems as one logical feature containing multiple windows it should probably also use single presenter. Then you would follow recommended approach: single context per presenter. You can call SaveChanges multiple times so it should not break your logic.
The source of this issue is well known problem with deficiency of dynamic proxies generated on top of POCO entities combined with Fixup methods generated by POCO T4 template. These proxies still hold reference to the context when you dispose it. Because of that they think that they are still attached to the context and they can't be attached to another context. The only way how to force them to release the reference to the context is manual detaching. In the same time once you detach an entity from the context it is removed from related attached entities because you can't have mix of attached and detached entities in the same graph.
The issue actually not occures in the code you call:
itemFromA.RelatedProperty = itemFromB;
but in the reverse operation triggered by Fixup method:
itemFromB.RelatedAs.Add(itemFromA);
I think the ways to solve this are:
Don't do this and use single context for whole unit of work - that is the supposed usage.
Remove reverse navigation property so that Fixup method doesn't trigger that code.
Don't use POCO T4 template with Fixup methods or modify T4 template to not generate them.
Turn off lazy loading and proxy creation for these operations. That will remove dynamic proxies from your POCOs and because of that they will be independent on the context.
To turn off proxy creation and lazy loading use:
var context = new MyContext();
context.ContextOptions.ProxyCreationEnabled = false;
You can actually try to write custom method to detach the whole object graph but as you said it was asked 500 times and I haven't seen working solution yet - except the serialization and deserialization to the new object graph.
I think you have a few different options here, 2 of them are:
Leave context alive until you are done with the process, use only 1 context, not 2.
a. Before disposing of context #1, creating a deep clone of graph, using BinaryStreamer or a tool such as ValueInjecter or AutoMapper.
b. Merge changes from context #2 into cloned graph.
c. Upon saving, merge changes from cloned graph into graph created by new ObjectContext.
For future reference, this MSDN blogs link can help decide you decide what to do when:
http://blogs.msdn.com/b/dsimmons/archive/2008/02/17/context-lifetimes-dispose-or-reuse.aspx
I don't think you need to detach to solve the problem.
We do something like this:
public IList<Contact> GetContacts()
{
using(myContext mc = new mc())
{
return mc.Contacts.Where(c => c.City = "New York").ToList();
}
}
public IList<Sale> GetSales()
{
using(myContext mc = new mc())
{
return mc.Sales.Where(c => c.City = "New York").ToList();
}
}
public void SaveContact(Contact contact)
{
using (myContext mc = new myContext())
{
mc.Attach(contact);
contact.State = EntityState.Modified;
mc.SaveChanges();
}
}
public void Link()
{
var contacts = GetContacts();
var sales = GetSales();
foreach(var c in contacts)
{
c.AddSales(sales.Where(s => s.Seller == c.Name));
SaveContact(c);
}
}
This allows us to pull the data, pass it to another layer, let them do whatever they need to do, and then pass it back and we update or delete it. We do all of this with a separate context (one per method) (one per request).
The important thing to remember is, if you're using IEnumerables, they are deferred execution. Meaning they don't actually pull the information until you do a count or iterate over them. So if you want to use it outside your context you have to do a ToList() so that it gets iterated over and a list is created. Then you can work with that list.
EDIT Updated to be more clear, thanks to #Nick's input.
Ok I get it that your object context has long gone.
But let's look at it this way, Entity Framework implements unit of work concept, in which it tracks the changes you are making in your object graph so it can generate the SQL corresponding to the changes you have made. Without attached to context, there is no way it can tack changes.
If you have no control over context then I don't think there is anything you can do.
Otherwise there are two options,
Keep your object context alive for longer lifespan like session of user logged in etc.
Try to regenerate your proxy classes using self tracking text template that will enable change tracking in disconnected state.
But even in case of self tracking, you might still get little issues.

How do I find the source of all the objects that are being tracked for changes in EF CodeFirst CTP5?

I'm having the 'An entity object cannot be referenced by multiple instances of IEntityChangeTracker' problem. After some checking around it seems like I have an object that's being tracked for changes. The problem is that I don't know the source of the problem object... it's obviously been put into the context, but I'm not sure which call hasn't been properly Detached.
So, after hours of trying to figure this out, I'm looking for how to walk the tree to find the source object that I'm having the conflict with, as maybe that will help me understand where the source object is being Added.
The error is being thrown on line 226, so it looks like I either have a 'stealth' Customer existing, or maybe one of the properties of Customer is causing this, as Customer has a couple other properties that are their own complex object types...
Line 224: if (null != this.Customer)
Line 225: {
Line 226: context.Entry(this.Customer).State = EntityState.Unchanged;
Line 227: }
The error doesn't say which object is causing the error, it just points at line 226. Upon assuming it's a phantom Customer object that's causing this, I've tried:
var test = ((IObjectContextAdapter)dataContext).ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);
foreach(var e in test)
{
if(e.GetType() == typeof(Customer))
{
dataContext.Detach(e);
}
}
The idea was to loop through the thing that holds references to all the objects, hopefully find the naughty Customer and give it the boot. But, alas, this didn't work; no Customers are found in this loop. Oh, FYI - this is run a few lines before the previous code so I'm not sneaking in any extra object creation there.
So I need a way to determine which object is in fact causing the error.
#Ladislav - FYI - I have a common library that contains all the business objects (BO). This common library is used by other projects - Windows Service, Web Service, etc. I've tried to make each BO responsible for populating and saving itself, so that I don't have one hugo data access class. Each BO is responsible for it's own Save() method. Here's an example of a current saveUpdate method:
public void SaveOrUpdate(DataContext context)
{
if (context.Entry(this).State == EntityState.Detached)
{
context.Customers.Add(this);
context.SaveChanges();
}
else //update
{
context.Entry(this).State = System.Data.EntityState.Modified;
context.SaveChanges();
}
}
In regards to your suggestion of scope, I've tried various strategies - At first blush everyone says do it atomically - so I had each method grabbing a new Instance of the DataContext to do it's work. This worked fine, as long as the objects weren't very complex, and didn't depend on each other, i.e. only contained base type properties like int and string.
But once I started getting these concurrency errors, I dug into it and found out that the DataContext somehow held on to references to objects even when it was disposed of That's a bit of a crazy-bad piece of engineering, IMHO. i.e. So if I add a Customer BO to the DataContext then allow the DataContext to go out of scope and be Disposed, and then spin up a new DataContext to do something, the original Customer BO pointer is still there!
So I read a bunch on StackOverflow (with many answers by you, I might add), Rick Strahl's treatise on DataContext Lifetime Management and the 8 Entity Framework Gotchas by Julia Lerman
So Julia says put in a Dispose method, and I did, but it didn't help, the DataContext is still magically holding onto the reference.
So Rick says try to use a 'global' DataContext, so that you only have one DataContext to worry about, and it should know everything that's going on, so it doesn't step on it's own toes. But that didn't seem to work either. To be fair, Rick is talking about Linq to SQL, and a web app, but I was kinda hoping it would apply to me too.
And then various answers say that you Don't want a Global DataContext, since it's going to get very big, very quickly, since it's holding all the info about all your objects, so just use DataContext for a Unit Of Work.
Well, I've broken down a Unit of Work to mean all changes, additions and updates done to a group of objects that you'd like done together. So for my Example Here are some BOs and properties:
MessageGroup
- Property: List
- Property: Customer
Customer
- Property: List
- Property: List
Message
- Property: Customer
- Property: MessageGroup
- Property: User
User
- Property: Customer
- Property: List
In the system when a MessageGroup arrives (as Xml), it's examined and parsed. The MessageGroup constructor used Dependency Injection and takes the DataContext as one of it's parameters - so all the 'child' BOs being created are using this one instance of the DataContext. The Customer is fetched from the database (or a new one is created) and assigned to the MessageGroup... let's assume it's an existing Customer - so no updates need to be done to it, it's fresh out of the DataContext.
Then the MessageGroup.Messages list is looped and the first Child BO to create is a new User object. I assign the same Customer object (from the MessageGroup) to the User. However, when context.Users.Add(this) is called, I get the error. If I don't assign the Customer to the User, I don't get the error.
So now I have a Customer (or a child property, I'm not sure) that's fresh from the DB, that I don't need tracked causing me angst. I thought I could just remove it from the context by using something like:
var cust = Customer.GetCustomerFromExternalId(crm.CustomerId);
dataContext.Detach(cust);
dataContext.SaveChanges();
But I still get the error, even though I've explicity removed it. Of course if it's one of the child properties of Customer, maybe that hasn't been removed?
Currently I'm wondering if the Repository Pattern is suitable for my purpose. I'm also wondering if EF CodeFirst is fundamentally flawed or just overly complex? Maybe I should use SubSonic or NHibernate instead?
As I know there is probably no clear way to get related context from POCO entity - all related properties of dynamic proxy are non public. For checking entities in DbContext use:
context.ChangeTracker.Entries<Customer>().Where(e => e.State == ...)
The best way to avoid your problems is using single context per "unit of work". You obviously don't follow this approach if you have entities from multiple contexts. Moreover it looks like you are using multiple concurrent alive contexts.

Categories