0

I received this exception while debugging in VS 2012

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

//_dbSet declaration: 

    private readonly IDbSet<T> _dbSet;


//Method parameter

    public virtual void Update(T entity)


//method fragment   



 public virtual void Update(T entity)
    {
        if (Entities == null) return;

        var entry = Entities.Entry(entity);

        switch (entry.State)
        {
            case EntityState.Modified:
                var currentValues = entry.CurrentValues.Clone();
                entry.Reload();
                switch (entry.State)
                {
                    case EntityState.Detached:
                        Entities.Entry(entry).State = EntityState.Modified;
                        break;
                    default:
                        entry.Reload();
                        entry.CurrentValues.SetValues(currentValues);
                        break;
                }
                break;
            case EntityState.Detached:
                _dbSet.Attach(entity); /*Here is the thing*/
                entry.CurrentValues.SetValues(entity);
                break;
        }
        Entities.Commit();
    }

I have spent almost a week trying to solve optimistic concurrency with these patterns: DbFactory, Unit of Work, DI, Generic Repository, without getting results.

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Felix Aballi
  • 899
  • 1
  • 13
  • 31

3 Answers3

0

I believe the exception message is clear enough:

An entity with the same key (that is, an entity that maps to the same database record) has already been loaded and attached in the target DbSet.

What you decide to do in that case is entirely up to you:

  • You can get the already loaded equivalent entry and modify the values of the attached equivalent to match the entity instance (or anything more complicated);
  • You can detach the equivalent loaded entry and attach your parameter entity instead;
  • You can just skip over it;
Jean Hominal
  • 16,518
  • 5
  • 56
  • 90
0

The code smells bad;

The first switch statement uses the entry.State and checking whether the entity is in modified state or in detached state; then in the modified case , a new switch statement is created to check whether the entity is detached or in other state.

The exception states nothing about the optimistic concurrency; instead it states that you are trying to attach an entity to the object context and an entity with the same key already exists in the context.

daryal
  • 14,643
  • 4
  • 38
  • 54
0

I would like to thank all of whom dedicated a bit of their precious time to my headake. Here is a new post clearifying my final solution for concurrent Update method in Generic Repository pattern. Nothing was lost thanks to this article: Seeking Entity's Key by Attribute Along

That was very useful: RoccoC5


private object GetKeyValue(T entity)
    {
        var key =
            typeof(T).GetProperties().FirstOrDefault(
                p => p.GetCustomAttributes(typeof(KeyAttribute), true).Length != 0);
        return (key != null) ? key.GetValue(entity, null) : null;
    } 

public virtual void Update(T entity) { if (Entities == null) return;

        var key = GetKeyValue(entity);
        var originalEntity = _dbSet.Find(key);
        Entities.Entry(originalEntity).CurrentValues.SetValues(entity);
        Entities.Commit();
   }
Community
  • 1
  • 1
Felix Aballi
  • 899
  • 1
  • 13
  • 31