Lareau
Lareau

Reputation: 2011

Why am I getting an InvalidOperationException when trying to re-attach an object

I had a bit of a struggle trying to understand why my code was crashing (which I got to work).

When you look at both the original method and the working one, the placement of one line is different

ctx.Inventories.Attach(this);

I'm puzzled when the original method doesn't work but the second one does. Can anyone provide some insight?

Here's the exception that I get.

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

This is my original method

  public void RemoveDependency(int depId)
    {
        bool returnValue = false;

        if (this.Id != 0 && depId > 0)
        {
            using (ApsEntities ctx = new ApsEntities())
            {
                var query2 = from d in ctx.Dependencies
                             where d.Id == depId
                             select d;

                Dependency found = query2.FirstOrDefault();

                if (found != null)
                {
                **ctx.Inventories.Attach(this);**
                    ctx.ObjectStateManager.ChangeObjectState(this, EntityState.Modified);
                    this.Dependencies.Remove(found);

                   ctx.SaveChanges();
                }
            }
        }

        return returnValue;
    }

Here is my working method

public void RemoveDependency(int depId)
{
    bool returnValue = false;

    if (this.Id != 0 && depId > 0)
    {
        using (ApsEntities ctx = new ApsEntities())
        {
            **ctx.Inventories.Attach(this);**

            var query2 = from d in ctx.Dependencies
                         where d.Id == depId
                         select d;

            Dependency found = query2.FirstOrDefault();

            if (found != null)
            {
                ctx.ObjectStateManager.ChangeObjectState(this, EntityState.Modified);
                this.Dependencies.Remove(found);

               ctx.SaveChanges();
            }
        }
    }

    return returnValue;
}

Upvotes: 1

Views: 1446

Answers (1)

Wouter de Kort
Wouter de Kort

Reputation: 39898

The behavior has to do with the ObjectStateManager tracking the relationships.

When the current Inventory item is not known to the ObjectContext (as in your first example) then the relationships between Inventory and Dependency is not recognized by the context. Since Inventory is unknown to the ObjectContext your query for a Inventory will load it and the item already exists when you attach it to your ObjectContext.

In the second example you first attach Inventory and then execute the query. The ObjectContext will then explicitly attach the Dependency object to the Inventory item.

The documentation states:

ObjectStateManager tracks query results, and provides logic to merge multiple overlapping query results. It also performs in-memory change tracking when a user inserts, deletes, or modifies objects, and provides the change set for updates. This change set is used by the change processor to persist modifications.

This behavior can't happen when the related objects are not known to the ObjectContext.

Upvotes: 3

Related Questions