Geeks With Blogs
Andrew Siemer's Blog Enterprise Web Applications, ASP.NET MVC, C#, SQL Server, Architecture, & Writing

I just had this error where entity framework was complaining about my object already being referenced by the data context that I originally got the object from.  In LINQ to SQL I guess this was just taken care of for me.  I would get the object in a using statement so that the data context was cleared when I was through with the context.  Then I could do what ever I wanted to with the object after that – to include throwing it back to the database.

I came across the fix to this issue here: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/501d7b99-0cb9-44b6-b2cd-16275a151b31 which simply suggests detaching the object from the original context before I kill that context.  Then I can re-attach the object to a new context later on.  This solved the issue…but uncovered more issues.

Here is my post to the MS forum:

-----------------------------------------------------------------------------------

Working in a web app I am very fond of the Repository approach.  I generally create a new context inside a using statement which then kills the context for me once my snippet of work is complete.  So for an AccountsRepository I might have a Save(Account account) method which would have something like the following:

using (RanchBuddyDataContext dc = new Connection().GetContext())

                {

                    if(account.AccountID > 0)

                    {

                        dc.Accounts.Attach(account, true);

                    }

                    else

                    {

                        dc.Accounts.InsertOnSubmit(account);

                    }

                    dc.SaveChanges();

                }

While this worked great in LINQ to SQL I am finding that it doesn't work so well with the Entity Framework.  I am now getting the error that started this thread.  In order to address this problem I have to do a few things and am not liking the work that goes into this.  Hopefully someone can adjust my way of thinking on this.


For my particular issue I have a person that logs into the system.  Once the log in is correct I stash their account object (fairly light) into their current session.  I then refer to that now and then as needed.  This works great.  However, when the user goes to the edit account screen, I would normally load the screen with their session held Account object.  Allow the user to edit their data and then throw it at a repository method as descibed above.


Not any more!


Up to the point where the user logs in is unchanged.  However, the object that is returned to me by my login method now has to be detached from the context - a step that I must remember any time that I want to keep and object out of the db, fiddle with it (edit it), and then eventually persist it back to the db.  Then it is put in the session for later use.  Once the user edits their account I have to get an original copy of the object (I am guessing so that the context is aware of it???) and then attempt to persist my object (with changes) back to the db.


I now have this code for getting the Account by username:

public Account GetAccountByUsername(string Username)

        {

            Account result = null;

            using (RanchBuddyEntities dc = connection.GetContext())

            {

result = dc.AccountSet.Where(a => a.Username == Username).FirstOrDefault();

                dc.Detach(result);

            }

            return result;

        }

If the account that is returned from a username search matches the supplied password then the account object here goes into my session.  Notice that at the bottom of my query above I have a dc.Detach(result) statement to remove it from the context.  From what I have read so far I have to do this so that I can re-attach it later on or keep a copy of the original object with me everywhere I go.


Then comes my save code.

using (RanchBuddyEntities dc = connection.GetContext())

                {

                    if(account.AccountID > 0)

                    {

                        Account original = dc.AccountSet.Where(a => a.AccountID == account.AccountID).FirstOrDefault();

                        dc.ApplyPropertyChanges("AccountSet",account);

                    }

                    else

                    {

                        dc.AddToAccountSet(account);

                    }

                    dc.SaveChanges();

                }

In this code I now have to get the original object into the context (as I don't carry the original object around with me just in case I need it and I guess the context is not aware of it if I don't manually load it??), then ApplyPropertyChanges of my updated object, and finally SaveChanges() on the context.


I would love to hear if anyone has a better way of working with this.  I much prefer the way I was able to do this in LINQ to SQL as there were less steps to remember and I didn't need to litter various methods with snippets so that one method would work correctly with another (when they shouldn't care about each other at all).

-----------------------------------------------------------------------------------

I would love to hear of a better solution to this problem that shouldn’t be a problem.

Posted on Friday, March 27, 2009 2:12 PM | Back to top


Comments on this post: Entity Framework : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

# re: Entity Framework : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Requesting Gravatar...
I am following-up to find out how your approach of calling "dc.Detach(result);" in your retrieve code is working for you now.
Left by Mark Kamoski on Jun 19, 2009 10:08 AM

# re: Entity Framework : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Requesting Gravatar...
Actually it worked fine. However, since this post I took all of about an hour and gutted all the Entity Framework crap out of my code base and went back to LINQ to SQL. EF is coming right along but is still a bit fraught with bugs...ERRR quirks! And they are slowing me down more than I care for. LINQ to SQL just flows and works as expected with a few limitations that I have long since worked through. Perhaps once EF 2.0 comes out I will try it again...but at this time if I need more complex mapping scenarios in place of the direct one to one mapping of LINQ to SQL I will go with NHibernate!
Left by Andrew Siemer on Jun 19, 2009 12:47 PM

# re: Entity Framework : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Requesting Gravatar...
Regarding this...
"I would love to hear if anyone has a better way of working with this"
...here are some suggestions...
...instead of this...
dc.ApplyPropertyChanges("AccountSet", account);
...I think one can do something like this...
dc.ApplyPropertyChanges(account.EntityKey.EntitySetName, account);
...which gets rid of some hardcode...
...and also I think that one should check like this...
targetEntity.EntityState == EntityState.Detached
...and if that returns true then one cannot do this...
myContext.Detach(targetEntity);
...because L2E cannot (ug) run Detach on an object that is already detached...
HTH.
-- Mark Kamoski
Left by Mark Kamoski on Jun 24, 2009 1:49 PM

# re: Entity Framework : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Requesting Gravatar...
thanks for sharing
Left by Andy on Jan 11, 2010 2:57 AM

# re: Entity Framework : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Requesting Gravatar...
I encountered this problem with the Entity Framework in my work with ASP.NET MVC recently.

I found that a more durable solution to this problem, is to ensure that you've only ever got one connection - I implemented this by create an abstract class with a static getter, resulting in a singleton pattern, like so:

namespace X {
public class App
{
private static MyEntities _DB;

public static MyEntities DB
{
get {
if (_DB == null) _DB = new MyEntities();
return _DB;
}
}
}
}

I can now do X.App.DB from anywhere to get the current connection instance.
Left by Rasmus Schultz on Feb 25, 2010 2:28 PM

# re: Entity Framework : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Requesting Gravatar...
I hope this is the simplest and correct solution. You need one db context per httprequest.

EF4 Code First template Global.asax.cs http://gist.github.com/574505

void MvcApplication_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Items[SessionKey] = new Db();
}

void MvcApplication_EndRequest(object sender, EventArgs e)
{
var disposable = HttpContext.Current.Items[SessionKey] as IDisposable;
if (disposable != null)
disposable.Dispose();
}

Left by hotfile on Mar 28, 2011 5:48 AM

# re: Entity Framework : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Requesting Gravatar...
You can try using the objectstatemanager; e.g.

dc.ObjectStateManager.ChangeObjectState(entity, EntityState.Unchanged)
Left by S Moore on Jul 01, 2011 6:52 AM

Your comment:
 (will show your gravatar)


Copyright © Andrew Siemer - www.andrewsiemer.com | Powered by: GeeksWithBlogs.net