Moin Khan
Moin Khan

Reputation: 37

Create: An entity object cannot be referenced by multiple instances of IEntityChangeTracker

I have created a page asp.net MVC for inserting records to database where i am giving a preview button to see how the data will looks on client side before saving it. I am using session to pass model to the preview page. On preview page i have created a button which will save the model in session to database but it is throwing exception "An entity object cannot be referenced by multiple instances of IEntityChangeTracker". I am using the same dbContext. I had tried many solutions given by users but they are not working for me. I have attached the part of the code that's throwing exception. Please see where I am doing wrong.

Here is the code where I am saving record

var model = Session[Constants.SessionVariables.ProjectModelForPreview] as Project;
if (create != null)
{
    if (model.Id == 0)
    {
        if (model.IsFeatured)
        {
            foreach (var item in dbContext.Projects.Where(p => p.IsFeatured == true))
            {
                item.IsFeatured = false;
            }
            dbContext.SaveChanges();
        }

        dbContext.Entry(model).State = EntityState.Unchanged;
        dbContext.SaveChanges();
        TempData["SuccessMessage"] = "Project created successfully.";
        return RedirectToAction("Index");
    }
}

Upvotes: 0

Views: 449

Answers (2)

George Vovos
George Vovos

Reputation: 7618

Let's ignore the original problem for now,it will be solved once you refactor the code

1)if for some reason you are using the same context across request ,stop. (I don't think you do though).

2)Don't save tracked entities in the Session* Search on google to see how EF tracks changes.

3)Read 1 and 2 again

*Use .AsNoTracking() or project your entity in a new model and save that in the session

Upvotes: 1

CodeCaster
CodeCaster

Reputation: 151720

Your controller, and therefore your DbContext, is instantiated per request. So your application follows this flow:

  • Request 1 instantiates DbContext 1.
  • You load an entity through DbContext 1. This entity is being tracked, and the entity itself holds a reference to DbContext 1.
  • You store this entity in the session, keeping the old DbContext alive. This works, because the default session state works InProc, and not by serialization.
  • Request 2 comes in, DbContext 2 gets instantiated.
  • The entity is retrieved from the session.
  • You try to save the entity, still being tracked by DbContext 1, through DbContext 2. This throws.

Now for the solution there are various approaches:

  • Don't save entities in the session at all. Persist them, and look them up again in successive requests.
  • Save entities in the session by manually serializing them.
  • Load the entity with .AsNoTracking().

Upvotes: 1

Related Questions