Bardicer
Bardicer

Reputation: 1469

Object already exists error when trying to update database object via Entity Framework

I am using the following method of trying to update an object using entity framework:

public static void UpdateItem(Item updatedObject) {

  using (var context = new DbContext())
  {
    context.MyObjectsPropertys.Attach(updatedObject);
    context.Entry(updatedObject).State = EntityState.Modified;
    context.SaveChanges();
  }
}

I get an error on the attach:

 An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.

If I try to change the Attach call to an Add call (object with same key already exists objectstatemanager) I get:

Cannot insert duplicate key in object 'database.Table'. The duplicate key value is (AttributeValue). The statement has been terminated.

I have found lots of questions regarding this error, but none of the answers work in my situation:

I tried deleting the "Attach" statement as well, and just doing the state change as suggested in Error multiple objects with the same key DbContext, but that didn't work either.

The most frustrating thing to me on this is that this is the exact same sequence of statements that successfully updates other things in the solution.

Upvotes: 0

Views: 3729

Answers (3)

Brian Rice
Brian Rice

Reputation: 3257

Here is how I handle it:

    public virtual void Update(TEntity entityToUpdate)
    {
        if (_db.Entry(entityToUpdate).State == EntityState.Added)
            return; // just been added leave state as added

        try
        {
            _dbSet.Attach(entityToUpdate);
        }
        catch (InvalidOperationException ex)
        {
            var trackedEntity = _dbSet.Find(GetKeyValues(entityToUpdate));
            if (trackedEntity == null)
                throw;
            if (_db.Entry(trackedEntity).State != EntityState.Unchanged)
                throw;
            _db.Entry(trackedEntity).State = EntityState.Detached;
            _dbSet.Attach(entityToUpdate);
        }
        _db.Entry(entityToUpdate).State = EntityState.Modified;
    }

    public object[] GetKeyValues(TEntity entity)
    {
        var objectContextAdapter = ((IObjectContextAdapter)_db);
        var name = typeof(TEntity).Name;
        var entityKey = objectContextAdapter.ObjectContext.CreateEntityKey(name, entity);
        var result = entityKey.EntityKeyValues.Select(kv => kv.Value).ToArray();
        return result;
    }

Upvotes: 0

Mohsen Esmailpour
Mohsen Esmailpour

Reputation: 11544

You must check if an entity with the same key is already tracked by the context and modify that entity instead of attaching the current one:

var trackedEntity = context.MyObjectsPropertys.Find(updatedObject.Id);
context.Entry(trackedEntity).CurrentValues.SetValues(updatedObject);
context.Entry(trackedEntity).State = EntityState.Modified;
context.SaveChanges();

Upvotes: 5

Parv Sharma
Parv Sharma

Reputation: 12705

you must be retrieving the same object and since then the object retrieved is being tracked by the DataContext object. Adding would certainly give an error because the key obviously is present in the dictionary.

I think you can retrieve the local entities using context.ChangeTracker.Entries() and then look for the same key if present

Upvotes: 1

Related Questions