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;
}
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
.