ObjectStateManager中已存在具有相同键的对象

时间:2011-10-17 21:09:08

标签: c# entity-framework-4 poco

此错误已被问及A LOT。但我认为没有一个案例适用于我的特定情况,或者至少不完全适用。

我正在创建一个具有2个导航属性的新实体,这些属性是集合。实体和导航属性都是数据库中不存在的新实体。我的问题是每当我尝试将实体附加到上下文时,如果其中任何一个集合有多个元素,我就会遇到上述异常。

我在以下代码中的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 个答案:

答案 0 :(得分:3)

  

实体和导航属性都是新实体   数据库中不存在。

然后问题是:为什么使用Attach?通过使用Attach,您告诉EF,数据库中的entites ,EF会将主键属性的值视为数据库中的PK列值。因为这些属性必须是唯一的,一旦你有两个具有相同键值的entite,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