【问题标题】:Why the Add method of my dbContext would be adding 2 parent entities and 1 child entity causing PK constrain error为什么我的 dbContext 的 Add 方法会添加 2 个父实体和 1 个子实体导致 PK 约束错误
【发布时间】:2017-10-18 07:03:00
【问题描述】:

短版: 在执行“myDbContext.Add(Entity)”时,我添加了 2 个实体,一个是我刚刚创建的,一个是我之前查询的,但还向 dbContext 添加了一个子实体(与我查询的第一个实体相关),似乎是 EF没有将它们跟踪为存在,因为正在尝试插入父实体和子实体。

由于政策原因,我无法添加特定代码,但基本上我正在做类似的事情:

using (var db = new MyEntitiesContext()) 
{
    /*don't know why, but code was already like this, 
    has some method which returns list of 
    SomeEntity type even knowing will have only 1 object*/

    List<SomeEntity> entities = new List<SomeEntity>
    entities = SomeMethod.SearchEntities(id);
    SomeEntity current = entities.FirstOrDefault();
    SomeEntity newOne = new SomeEntity();

    //Then notice I use some of the values (all of them are int/string/date)
    //from the "current" object to populate the "newOne"
    newOne.Id =  (from p in db.SomeEntities select p.Id).Max() + 1;
    newOne.SomeDateValue = current.SomeDateValue;
    newOne.someStringValue =  current.someStringValue;
    .
    . //add some other values which doesnt' seem relevant to the issue
    .
    db.SomeEntity(newOne);
    db.SaveChanges();           

}

由于某种原因,SaveChanges 方法会导致与违反 PK 约束的子实体相关的异常。

在调试并做了一些“观察”之后,我注意到我的 dbContext 对象“db”实际上包含 SomeEntity 的 2 个实体,即“newOne”和“current”,因为db.SomeEntity.Local 属性。

出于某种原因(糟糕的设计/理解),这样做时:

db.SomeEntity.Add(newOne) 

“当前”实例与子实体“状态”一起添加,因此 SaveChanges() 尝试重新插入现有的“状态”实体(除了现有的“当前”实体),这是抛出SaveChanges() 方法中的异常。

似乎我可以通过分离导致冲突的对象来解决这个问题,这些对象是“当前”实体,它是 dbContext 对象的子实体“状态”,但是

为什么会这样?或者我该如何避免?

我唯一的假设是,将值从“current”分配给“newOne”时的某些引用可能会导致该行为,请注意“status”子实体没有从“current”分配给“newOne”,我我尝试使用“状态”实体的新实例进行分配并将其保留为空,但这些都不能解决问题。

注意:我尝试在不同的“使用”块中查询“当前”对象,但问题仍然存在。

注意 2:在 SaveChanges 方法之前,代码编译和执行良好,上面的示例不是实际代码,而是一个缩短/虚构版本,试图代表存在问题的实际代码的同一部分,所以可以在上面的代码中找到一些语法/其他错误,这个问题更多地与我对实体框架如何工作和/或在添加/保存更改时跟踪实体缺乏了解

上次更新 SearchEntities 方法使用不同的上下文,通过在不同的上下文中“缓存”实体,我导致 EF 将它们标记为 new-for insert,我只是将该方法的代码取出以在同一个 dbContext 中使用它正在插入一个新实体并解决了这个问题,这似乎是一个非常常见的问题,但由于它的性质,每个开发人员都觉得自己陷入了陷阱。

【问题讨论】:

  • 您是否确保您的“类似”代码也可以编译并产生相同的问题
  • @Damien_The_Unbeliever 不,遗憾的是我刚刚创建的示例确实按预期工作,实际上我在 db 对象中看到了 2 个“SomeEntity”,但子实体没有被添加到 db 对象并且 SaveChanges 方法执行时没有错误,因此问题不存在,但即使在分离子实体时的“真实”问题中,“当前”也会导致其表上的 PK 冲突
  • 我认为上下文将包含 2 个值,因为被跟踪的实体..
  • @RJ- 嗨,是的,这似乎是意料之中的,我刚刚创建了一个只有 2 个表的快速示例,我看到这种行为和插入效果很好,但似乎有问题的实际代码正在做出了点问题或者模型搞砸了(很多人都接触过那个应用程序),在代码有问题的情况下,我还看到了 2 个实体,buuuuut 我还添加了一个子“状态”实体并导致主键约束错误,即使我分离子实体,父“当前”也会导致另一个错误,因为 EF 试图插入它(并且已经存在于表中)

标签: c# asp.net-mvc entity-framework


【解决方案1】:

我刚刚意识到使用来自其他 dbContext 的实体会导致问题,返回通用列表的方法 SearchEntities 使用不同的上下文。

似乎外部上下文“不知道”这个实体并将它们标记为新的以插入它们。

我从“SearchEntities”中取出代码来获取实体列表并解决问题。

其他可能的解决方案是分离每个实体或将其标记为“未更改”

感谢@GertArnold 的评论最终让我找到了正确的道路和解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-15
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    相关资源
    最近更新 更多