53

I have following code to add or update the Entity object. finding the object by primary key, based on the response I am adding or updating the object.

Adding record works, but during update its giving this error message "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key"

In my MSSQL database I have only one record.

var v = db.Envelopes.Find(model.ReportDate, model.Service);
if (v == null)
{
    db.Envelopes.Add(model);
    db.SaveChanges();
    ViewBag.status = "Record Add successfully";
    ModelState.Clear();
}
else
{
    db.Entry(model).State = EntityState.Modified;
    db.SaveChanges();
}

How can I fix this error message?

Mathieu
  • 4,449
  • 7
  • 41
  • 60
sfgroups
  • 18,151
  • 28
  • 132
  • 204

6 Answers6

89

As mentioned by @anon you can't attach model once you loaded the entity with the same key. The changes must be applied to attached entity. Instead of this:

db.Entry(model).State = EntityState.Modified;

use this:

db.Entry(v).CurrentValues.SetValues(model);
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • 2
    It looks promising but it caused "The property 'ID' is part of the object's key information and cannot be modified." So, is there any way to remove primary key from the model? – San Sep 19 '11 at 17:13
  • 3
    @Sanghoon You might get that error if the ID of `model` differs from the ID of `v`. So you might want to add something like `model.SetId(v.GetId());` before the call to `SetValues`. – sroes Sep 08 '13 at 18:47
  • @Ladislav Mrnka Thank you very much! This was the most straightforward solution I found. I was hoping that EF provided a simple "insert, if duplicate update" (or "update, insert if doesn't exist") all in one command but never found such a thing. Too bad, it's really a useful pattern and should be simpler IMHO. – William T. Mallard Jan 03 '14 at 07:07
9

If an earlier query read the entity to be updated and that's why you're getting the error, you can change that query to AsNoTracking. See the AsNoTracking example in: http://www.asp.net/entity-framework/tutorials/advanced-entity-framework-scenarios-for-an-mvc-web-application

tdykstra
  • 5,880
  • 2
  • 23
  • 20
7

I assume you are saying that your error occurs here:

db.Entry(model).State = EntityState.Modified;

Once you execute Find(), your Envelope is already being tracked by your context. This means that if you need to change a property, just change it on v, and then call SaveChanges(). Don't worry about setting the state to Modified.

anon
  • 4,578
  • 3
  • 35
  • 54
  • 3
    Correct. I tried using a new Context to get round this but it didn't work either. ObjectTracker still had a reference to it. – JTew Nov 12 '11 at 03:59
5

If you set your context to AsNoTracking() this will stop aspmvc tracking the changes to the entity in memory (which is what you want anyway on the web). Don't forget the using statement.

using System.Data.Entity;

db.Envelopes.AsNoTracking().Find(model.ReportDate, model.Service);

I got this from this forum post -> http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/advanced-entity-framework-scenarios-for-an-mvc-web-application

David Swindells
  • 641
  • 1
  • 12
  • 28
3

I'm using this because I have already created a new instance, and populated the properties I need to update.

var key=this.CreateEntityKey("Envelopes",model); 
        ObjectStateEntry ose;
        if(this.ObjectStateManager.TryGetObjectStateEntry(key, out ose)){
            var entity=(Page)ose.Entity;
            Envelopes.Detach(entity);
        }
            this.Envelopes.Attach(model);
Maslow
  • 18,464
  • 20
  • 106
  • 193
0

And another approach to solve the issue is detaching tracked entity and re-attaching the modified one. See my solution here.

Alexander Christov
  • 9,625
  • 7
  • 43
  • 58