MyDbContext dbContext = new MyDbContext(); var result = dbContext.Test.AsNoTracking().FirstOrDefault(x => x.Id == 1); result.Title = "11111"; dbContext.Update(result); dbContext.Entry<Test>(result).State = EntityState.Modified; dbContext.SaveChanges(); var result1 = dbContext.Test.AsNoTracking().FirstOrDefault(x => x.Id == 1); result1.Title = "22222"; dbContext.Update(result1); dbContext.Entry<Test>(result1).State = EntityState.Modified; dbContext.SaveChanges();
当更新同一个实体的时候报:The instance of entity type 'Test' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
很简单,在第一段和第二段之间加入
dbContext.Entry<Test>(result).State = EntityState.Untrack;
或者使用两个using(dbcontext){}别在同一个数据上下文
你用同一个数据上下文,
var result = dbContext.Test.AsNoTracking().FirstOrDefault(x => x.Id == 1);
result.Title = "11111";
dbContext.Update(result);
dbContext.Entry<Test>(result).State = EntityState.Modified;
dbContext.SaveChanges();
先不追踪的查出来了,然后更改,然后改变实体状态为追踪(Modified),此时你的实体状态已经是追踪状态了
然后你又来一遍,又查出来一个实体,也是追踪追踪状态
所以报错只能有一个追踪的实体去保存
明白原因了,我这里只是举了个项目中的例子,result和result1有可能是通过不同的查询条件得到的相同实体,而且Update都是封装的方法,每次调用这个方法后再声明一下 实体的 State 为EntityState.Untrack?
@Impossible:
换个思路,多次操作一个实体然后只保存一次
yDbContext dbContext = new MyDbContext();
var result = dbContext.Test.AsNoTracking().FirstOrDefault(x => x.Id == 1);
result.Title = "11111";
var result1 = result;
result1.Title = "22222";
dbContext.Update(result1);
dbContext.Entry<Test>(result1).State = EntityState.Modified;
dbContext.SaveChanges();
@Impossible:
声明一下 实体的 State 为EntityState.Untrack是可以的
每次用dbcontext的new一个其实也可以,没你想的那么严重
@猝不及防: DbContext是注入的,不能每次都new一个。而且这个Update(T entity),都是封装好的方法,在项目中result和result1不是每一次都相同,问题中的这个也只是举例。
@Impossible: 每次save完了你就把这个实体untrack,这不就统一了吗
在同一个 DbContext 实例中,被跟踪的实体只要 Key 相同,EF Core 就认为是同一个实体。
有没有什么解决方法,我问题中只是举了个例子,现在明白什么原因了。
项目中有很多这种情况,先查询某条数据,更新这条数据的某个值,然后在修改传入的对象,查询的数据和要修改的对象可能Key会相同,这时Update的时候就会这样,因为DbContext都是注入的,也不能每次都实例化多次DbContext吧,这样处理肯定不好。
@Impossible: 既然是更新操作,为什么加 AsNoTracking()
?直接让 EF 自动跟踪不是更好吗?
@dudu: 不加 AsNoTracking(),他们也是在同一个DbContext中更新的,也是会出现同样的问题。
@Impossible: 要去掉 EntityState.Modified
@dudu: 去掉也是报一样的错。