views:

5264

answers:

6

I have a model in Ado.Net EF. I have a one to many relation and when I want to Add the entities I get the error

"An entity object cannot be referenceed by multiple instances of IEntityChangeTracker"

Any clue?

Something similar to

Template template = new Template();
...
...
while (from < to)
{
    Course course = new Course();
    .....
    template.Course.Add(course);
    .....
}
courseEntities.AddToTemplate(template); // Problem line
courseEntities.SaveChanges();
+1  A: 

"template", or something that it references, has already been added to courseEntities or another context. I don't see anything in the code you show it would do that, but it is certainly happening. Perhaps it's happening in some of the code that you've trimmed. Look at the EntityState property of "template" in the debugger, and look at the EntityState of the properties of "template" as well. This should help you find out which entity instance is already in a context.

Craig Stuntz
A: 

I already realize the problem. I have another relation and I get the other entity from another context.

Mariano
+5  A: 

Hi,

I was getting this message until i started to store the data context in the HttpContext.Items Property. This means you can use the same data context for the current web request. That way you don't end up with 2 data contexts referencing the same entities.

Here is a good post on DataContext Life Management.

I hope it helps.

Dave

CraftyFella
A: 

Let me relate my experience with this nasty error and point out the terrain chasing it will take you over leading to a tremendously simple solution.

CompanyGroup is pretty simple. It has a name and it has a Company object.

I started with this:

1        public static void Add(CompanyGroup item)
2        {
3            try
4            {
5                using (Entities scope = new Entities())
6                {
7             scope.AddToCompanyGroup(item);
8                       scope.SaveChanges();
9                }
10            }
11            catch (Exception ex)
12            {
13                LogException(ex, item);
14                throw;
15            }     
16  }   

And got this error:

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

So, I added this between lines 6 and 7:

        (IEntityWithChangeTracker)item).SetChangeTracker(null);

That rewarded me with:

{"The object cannot be added to the ObjectStateManager because it already has an EntityKey. Use ObjectContext.Attach to attach an object that has an existing key."}

So I changed

scope.AddToCompanyGroup(item);

to

scope.Attach(item);

Now it complained about:

{"An object with a temporary EntityKey value cannot be attached to an object context."}

(beginning to sound like some of the girls I dated in my youth -- never content -- but I digress)

So I made the entity key null (didn't work) and used the method to create new (didn't work, either)

Along the way, I got this error, too:

{"The source query for this EntityCollection or EntityReference cannot be returned when the related object is in either an added state or a detached state and was not originally retrieved using the NoTracking merge option."}

The Solution?

Replace the core, lines 7 and 8, with:

                CompanyGroup newcg = new CompanyGroup();
                newcg.GroupName = item.GroupName;
                newcg.Company = scope.Company.Where(c => c.CompanyID == item.Company.CompanyID).First();

      scope.AddToCompanyGroup(newcg);
                scope.SaveChanges();

Essentially, I took the data passed via 'item', and moved it to newly created object of the same type that introduces the same scope as the one used in the Add.

+1  A: 

Please take a look at this.

This is the answer.

Barbaros Alp
A: 

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();
}
Daniel Steigerwald