Объект с тем же ключом уже существует в ObjectStateManager

#c# #entity-framework-4 #poco

#c# #entity-framework-4 #poco

Вопрос:

Об этой ошибке МНОГО спрашивали. Но ни один из случаев, которые, я думаю, не применимы к моему конкретному случаю, или, по крайней мере, не совсем.

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

Я получаю эту ошибку в Attach() инструкции в следующем коде:

 using (var context = new NSModel())
{
    context.Notifications.Attach(e);
    context.ObjectStateManager.ChangeObjectState(e,
    StateHelpers.GetEquivalentEntityState(e.State));

    foreach (NavigationProperty1 np in e.NavigationProperty1s)
        context.ObjectStateManager.ChangeObjectState(np,
        StateHelpers.GetEquivalentEntityState(np.State));

    foreach (NavigationProperty2 np in e.NavigationProperty2s)
        context.ObjectStateManager.ChangeObjectState(np,
        StateHelpers.GetEquivalentEntityState(np.State));

    context.SaveChanges();
    return e;
}   
  

Код предназначен для веб-сайта, поэтому объекты не имеют состояния, а контекст создается и удаляется при каждом вызове…

Есть идеи?

Ответ №1:

И объект, и свойства навигации являются новыми объектами, которых нет в базе данных.

Тогда возникает вопрос: почему вы используете Attach ? С помощью Attach вы сообщаете EF, что объекты находятся в базе данных, и EF будет рассматривать значения свойств первичного ключа как значения столбца PK в базе данных. Поскольку эти свойства должны быть уникальными, EF будет жаловаться, как только у вас будет два объекта с одинаковыми значениями ключа. Вполне возможно, что у вас такая ситуация, когда вы автоматически создаете идентификаторы в качестве свойств ключа и не задаете значения при создании объектов.

Простой пример:

 public class Parent
{
    public Parent
    {
        Children = new List<Child>();
    }

    public int Id { get; set; }
    public ICollection<Child> Children { get; set; }
}

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

Этот код …

 using (var ctx = new MyContext())
{
    var parent = new Parent();
    var child1 = new Child();   // <- Id is 0
    var child2 = new Child();   // <- Id is 0 as well

    parent.Children.Add(child1);
    parent.Children.Add(child2);

    ctx.Parents.Attach(parent);  // <- exception here

    //...
}
  

… выдаст ваше исключение, потому что EF пытается присоединить два разных дочерних экземпляра с одним и тем же ключом 0 . Когда подключается второй дочерний child2 элемент, он говорит: «Объект (а именно child1 ) с тем же ключом (а именно 0 ) уже существует в ObjectStateManager».

Если вы хотите добавить весь граф объектов в качестве новых объектов в базу данных, вы можете просто вызвать context.Notifications.AddObject(e); вместо Attach .

Комментарии:

1. Спасибо… На самом деле я заставил его работать с помощью attach(), но ваши решения более чистые и элегантные.