Entity Framework中Update实体,在修改状态时引发主键冲突的问题

leonken88 2018-02-17 05:18:56
比如有两个实体,Class班级,Student学生。一个班级有多个学生。
场景:
查出某个班级的所有学生(同时包含班级信息) -> 然后修改学生信息 -> 修改实体状态 -> 提交数据库

重点在于我使用AsNoTracking()不跟踪查询结果的实体状态,以及Include()预加载学生班级实体。这样的结果就使得查出来的List<Student>脱离上下文的状态管理,同时每一个实体都包含同一个班级对象。

关系图:


查询代码:

List<Student2> studens;
using (MyDbContext db = new MyDbContext())
{
studens = db.Student2
.AsNoTracking() //重点
.Include("MyClass") //重点
.Where(r => r.ClassId == 1).ToList(); //具体是哪个班级不重要,这里只是测试,班级也可能是不固定的
}


修改Student数据:

studens[0].StuName = "新名字1";
studens[1].StuName = "新名字2";


修改实体状态,提交数据库:

using (MyDbContext db = new MyDbContext())
{
foreach (var i in studens)
{
var entry = db.Entry(i); //问题就出在Loop循环第二次
entry.State = System.Data.Entity.EntityState.Unchanged;
entry.Property(r => r.StuName).IsModified = true;
}

db.SaveChanges();
}


ERROR:Attaching an entity of type 'Entity.TableClass' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

原因就是所有的实体都是非跟踪的,所有的Student List引用的班级对象是同一个,主键ID是一样的,所以在第二次var entry = db.Entry(i);的时候就冲突了。

目前能想到的办法是 1.手动将所有MyClass导航属性置为null,然后提交数据库。缺点是很麻烦。
不知道有没有好的解决方案
...全文
2233 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
笑容融化坚冰 2018-02-20
  • 打赏
  • 举报
回复
没遇到过这种需求场景。原因是导航属性实体同样被附加到上下文,且EntityState同样被设置为Unchanged,第二次又尝试附加同主键的实体就报错。 可试试在循环最后一句加上db.Entry(i.MyClass).State = EntityState.Detached;
leonken88 2018-02-20
  • 打赏
  • 举报
回复
引用 3 楼 daixf_csdn 的回复:
我觉得不是你所认为的问题。根据这个错误提示看,就是Context管理的问题,使Context中有了两条相同主键的记录。 不知道你这个异常,是出现在SaveChange时,还是SaveChanges之前。 如果是savechanges之前的异常: 原因应该是,在第一次循环时,检查MyClass导航属性时,EF发现导航属性没有相关数据,因此新增了一条ClassId=1的班级数据。 第二次循环,也有可能会新增同样的一条班级数据,从而导致班级数据重复。 如果是savechanges时的异常,那么应该就是第一次循环生成的新记录在savechange时,和数据库已有班级记录产生冲突。和第二次循环不一定有关系。 要解决这个问题,方法估计是:循环前,预先加载班级的相关数据。
我再试试,有结论我在回帖,谢谢
秋的红果实 2018-02-20
  • 打赏
  • 举报
回复
用EF的事务处理,将每个update放到一个EF事务中 EF6.0以及以后版本,默认下,会将语句包裹在一个事务中
leonken88 2018-02-20
  • 打赏
  • 举报
回复
引用 3 楼 daixf_csdn 的回复:
我觉得不是你所认为的问题。根据这个错误提示看,就是Context管理的问题,使Context中有了两条相同主键的记录。 不知道你这个异常,是出现在SaveChange时,还是SaveChanges之前。 如果是savechanges之前的异常: 原因应该是,在第一次循环时,检查MyClass导航属性时,EF发现导航属性没有相关数据,因此新增了一条ClassId=1的班级数据。 第二次循环,也有可能会新增同样的一条班级数据,从而导致班级数据重复。 如果是savechanges时的异常,那么应该就是第一次循环生成的新记录在savechange时,和数据库已有班级记录产生冲突。和第二次循环不一定有关系。 要解决这个问题,方法估计是:循环前,预先加载班级的相关数据。
是在savechanges之前,就是调用Entry()的时候,现在就是因为预先加载了班级数据,才导致这个问题(因为多个学生,引用的同一个班级信息[包括ID]),所以update之前得先把班级清空,但这样比较麻烦,不知道有没有其他好办法呢
圣殿骑士18 2018-02-20
  • 打赏
  • 举报
回复
我觉得不是你所认为的问题。根据这个错误提示看,就是Context管理的问题,使Context中有了两条相同主键的记录。 不知道你这个异常,是出现在SaveChange时,还是SaveChanges之前。 如果是savechanges之前的异常: 原因应该是,在第一次循环时,检查MyClass导航属性时,EF发现导航属性没有相关数据,因此新增了一条ClassId=1的班级数据。 第二次循环,也有可能会新增同样的一条班级数据,从而导致班级数据重复。 如果是savechanges时的异常,那么应该就是第一次循环生成的新记录在savechange时,和数据库已有班级记录产生冲突。和第二次循环不一定有关系。 要解决这个问题,方法估计是:循环前,预先加载班级的相关数据。
leonken88 2018-02-17
  • 打赏
  • 举报
回复
引用 1 楼 daixf_csdn 的回复:
既然要更新,为什么又用AsNoTracking?
因为对实体进行业务处理不是在DAL层,即使不用AsNoTracking,数据到了业务层也早已经没有跟踪状态了,一样的
圣殿骑士18 2018-02-17
  • 打赏
  • 举报
回复
既然要更新,为什么又用AsNoTracking?

62,046

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧