Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ObjectStateManager.TryGetObjectStateEntry returns false for attached object

TryGetObjectStateEntry returns false but when i try to attach the entity i get 'An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.'

The entity key is of type Guid.

How is this possible?

Edit: i am attaching 2 entities with different key. the error occurs always on the second entity of this type that i attach. if i swap them the error is still on the 2nd one.

    public bool IsAttached<T>(T obj) where T : class
    {
        ObjectStateEntry entry = null;

        ObjectContext objCtx = GetObjectContext();

        bool isKeyAttached = false;

        EntityContainer container = objCtx.MetadataWorkspace.GetEntityContainer(objCtx.DefaultContainerName, DataSpace.CSpace);
        EntitySetBase entitySet = container.BaseEntitySets.Where(item => item.ElementType.Name.Equals(typeof(T).Name)).FirstOrDefault();
        System.Data.EntityKey key = objCtx.CreateEntityKey(entitySet.Name, obj);

        if (objCtx.ObjectStateManager.TryGetObjectStateEntry(key, out entry))
        {
            isKeyAttached = entry.State != System.Data.EntityState.Detached;
        }

        return isKeyAttached;
     }
like image 774
Jeroen Avatar asked Oct 29 '11 11:10

Jeroen


1 Answers

This problem can occur if the entities you attach have navigation properties refering to other entities. Example:

public class Parent
{
    public int Id { get; set; }
    public Child Child { get; set; }
}

public class Child
{
    public int Id { get; set; }
}

The following code will throw an exception:

using (var context = new MyDbContext())
{
    var parent = new Parent { Id = 1 };
    var child1 = new Child { Id = 1 };
    parent.Child = child1;

    var child2 = new Child { Id = 1 };  // same key

    context.Children.Attach(child2);    // child with key = 1 is attached now

    var objContext = ((IObjectContextAdapter)context).ObjectContext;

    ObjectStateEntry entry;
    bool isAttached = objContext.ObjectStateManager.TryGetObjectStateEntry(
        new EntityKey("MyDbContext.Parents", "Id", parent.Id), out entry);
    // isAttached will be false because a Parent with Id = 1 is not attached
    if (!isAttached)
    {
        // we assume now that we could attach the parent safely
        context.Parents.Attach(parent);

        // Assumption is wrong -> Exception, because Attach attaches the whole
        // object graph, so it tries also to attach child1 together with parent
        // But child1 has the same key as child2 which is already attached
    }
}

So, the point is that TryGetObjectStateEntry only checks the state of the base entity and doesn't consider any navigation properties. Attach on the other hand does not only attach the base entity but also the children which are not yet attached, leading to the exception.

like image 51
Slauma Avatar answered Oct 10 '22 18:10

Slauma