ObjectStateManager.TryGetObjectStateEntry возвращает false для присоединенного объекта - PullRequest
5 голосов
/ 29 октября 2011

TryGetObjectStateEntry возвращает false, но когда я пытаюсь присоединить сущность, я получаю «Объект с таким же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом. '

Ключ сущности имеет тип Guid.

Как это возможно?

Редактировать: Я присоединяю 2 сущности с разными ключами. ошибка возникает всегда на втором объекте этого типа, который я присоединяю. если я поменяю их местами, ошибка все еще на втором месте.

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

1 Ответ

1 голос
/ 29 октября 2011

Эта проблема может возникнуть, если присоединяемые объекты имеют свойства навигации, ссылающиеся на другие объекты. Пример:

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

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

Следующий код выдаст исключение:

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

Итак, смысл в том, что TryGetObjectStateEntry только проверяет состояние базового объекта и не учитывает никаких навигационных свойств. Attach, с другой стороны, не только присоединяет базовую сущность, но и дочерние элементы, которые еще не присоединены, что приводит к исключению.

...