此错误已被问及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;
}
代码用于网站,因此实体是无状态的,每次调用都会创建和处理上下文......
有什么想法吗?
答案 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
。