2013-04-09 62 views
1

当我尝试新的子关系添加到现有的父对象的新子插入,实体试图插入父对象为,而不是更新它修改。我得到一个错误,说它试图插入一个重复密钥现有父实体框架4

这真的让我感到困惑,直到我用新的关系更新模型(通过数据库更新而不是代码优先)之后,它才表现得像这样。其他表在相同的情况下,具有相同的多对多模式不会导致此错误!

我发现,如果我将我的子对象添加到上下文中,请仔细设置ID值而不是导航属性,它将保存正常。 但是修复过程不会将子对象添加到导航集合,这会导致其他位置出现逻辑问题。

我的模型有一个多对多的关系是这样的:

选项 - < optionUnit> - 单位

两个选项和单元对象现有加载到上下文。

通常我会做网桥表,并设置像下面的导航属性:

bridge = new OptionUnit() 
{ 
    OptionUnitId = Guid.NewGuid(), 
    Unit = SelectedUnit, 
    Option = SelectedOption, 
}; 
//Context.OptionUnits.Add(bridge); //added to context via the navigation properties 

但是,当我这样做的时候,实体试图插入SelectedOption新的(即使它的实体状态在时间体改的保存,不是新的或分离的)。

为了解决这个问题,我不得不做桥,并设置ID的唯一。我在保存时没有错误,但它不会像我所期望的那样通过修复自动添加到SelectedOption.OptionUnits中。如果我手动将它添加到集合中,则会再次出现保存错误。

bridge = new OptionUnit() 
{ 
    OptionUnitId = Guid.NewGuid(), 
    //Unit = SelectedUnit, 
    UnitId = SelectedUnit.UnitId, 
    //Option = SelectedOption, 
    OptionId = SelectedOption.OptionId, 
}; 
Context.OptionUnits.Add(bridge); 

这似乎只发生在关于Options Entity的关系上。 optionUnit> - Unit之间的另一个关系没有问题,并按预期工作。

看起来好像他们的关系错了,但我不确定在哪里看。 我需要知道什么导致这种行为,如何解决它,以及如何防止它在未来发生......

回答

0

我发现了这个问题。添加子项后,我会运行一些逻辑来更新一些总数。问题是我用RaiseDataMemberChanged(“sum”)而不是RaisePropertyChanged(“sum”)。 RaiseDataMemberChanged()必须将实体中的某些内容标记为修改过的内容,这是造成这个问题的原因。 感谢IronMan84的帮助。

3

令人难以置信的是,朱莉Lerman只是有一个惊人的MSDN文章关于这个确切的问题,为什么它发生。你可以找到文章right here

在朱莉自己的话说:

它发生的原因是,当您使用DbSet.Add方法,不仅是根实体的状态标记为“增加”,但一切都在图表中该上下文之前并不知道被标记为已添加。尽管开发人员可能知道该对象具有现有的Id值,但实体框架将授予其EntityState(已添加)并为该对象创建一个Insert数据库命令,而不管现有Id如何。

所以这里简要介绍的是,当你说Context.OptionUnits.Add(bridge);时,它也认为你正试图为它添加Option和Unit对象。相反,你需要使用FK(如她所提到的)然后添加它。

我认为这就是你在第二次尝试时所要做的,但我想知道你是如何检查它是否在SelectedOption.OptionUnits。试图在保存后检查它吗?在这种情况下,它不会显示出来,因为该值在被Entity Framework拉出时被缓存在内存中。之后您需要尝试再次提出该对象。

+0

感谢您的文章!我现在正在阅读它,它似乎确认它应该如何工作,因为我不是处于断开连接状态时的工作方式 “当您在客户端应用程序中工作时,或者在单个单元中执行这些步骤时在上下文跟踪所有活动的情况下工作,这是您可能期望的行为,但是,如果您使用断开连接的数据,则行为会非常不同,这让很多开发人员感到惊讶。 – Shaboboo 2013-04-10 15:48:03

+0

将新对象添加到上下文之后,我期望“修复”过程应该通过并将相关实体连接在一起。然后该选项应该在OptionUnit的导航集合中包含OptionUnit。我希望在保存之前发生这种情况,就像我在应用程序中的其他地方一样。 我在将它添加到上下文后使用ExistingOption.UnitOptions.Contains(newUnitOption)对其进行检查。 – Shaboboo 2013-04-10 15:53:25

+0

只需将它添加到上下文中就行不通,因为在调用SaveChanges之前,您尚未保存它。 – IronMan84 2013-04-10 15:56:14