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

Go To StackoverFlow.com

1

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;
}
2012-04-04 17:33
by Lareau
Common refrain: Define "doesn't work". If it's an exception, post the exception. If it is undesirable behavior, post the desirable behavior and what the actual result is - Chris Benard 2012-04-04 17:41
Sorry Chris, I've attached it. It slipped my mind - Lareau 2012-04-04 18:01


3

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.

2012-04-04 17:54
by Wouter de Kort
Thanks for the quick answer. I'll keep this in the back on my head in the future to make sure it never happens again - Lareau 2012-04-04 18:09
Ads