参考:https://blog.csdn.net/qq_18638761/article/details/107833999
https://www.cnblogs.com/stgp/p/12294454.html
发生的原因,在CheckProductionCode()方法中根据主键id查询对象时没有使用AsNoTracking(),示例:_db.Productions.AsNoTracking()
那么EF会把查询出的对象缓存并跟踪对象状态,之后再Update的时候就会查询现有已跟踪的对象,发现已经存在一个相同主键的对象,所以报错。
https://www.cnblogs.com/stgp/p/12294454.html
发生的原因,在CheckProductionCode()方法中根据主键id查询对象时没有使用AsNoTracking(),示例:_db.Productions.AsNoTracking()
那么EF会把查询出的对象缓存并跟踪对象状态,之后再Update的时候就会查询现有已跟踪的对象,发现已经存在一个相同主键的对象,所以报错。
/// <summary> /// 编辑修改商品 /// </summary> /// <param name="dto"></param> /// <exception cref="Exception"></exception> public void EditProduction(Production dto) { bool res = CheckProductionCode(dto); if (!res) { throw new Exception("商品编码重复"); } _db.Productions.Update(dto); _db.SaveChanges(); }
CheckProductionCode
public bool CheckProductionCode(Production dto) { var res = _db.Productions.Where(x => x.ProductionId == dto.ProductionId).FirstOrDefault(); //.... return true; }
解决办法1:查询的时候禁用状态跟踪 _db.Productions.AsNoTracking()
解决办法2:在Program.cs中配置数据库的时候,设置所有查询禁用跟踪
// 使用 Pomelo.EntityFrameworkCore.MySql builder.Services.AddDbContext<DataMgrContext>(opt => { string connStr = builder.Configuration.GetConnectionString("MysqlContext") + ""; var serverVersion = ServerVersion.AutoDetect(connStr); opt.UseMySql(connStr, serverVersion); //重要,不跟踪查询得到的实体。 opt.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); });
注意,一旦设置了AsNoTracking() 或 opt.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); 后,查询出来的对象,修改属性,然后_db.SaveChanges();这样的方法就不能修改成功了。
需要使用 _db.Productions.Update(dto); _db.SaveChanges();这样的方式才行。
/// <summary> /// 编辑修改商品 /// </summary> /// <param name="dto"></param> /// <exception cref="Exception"></exception> public void EditProduction(Production dto) { bool res = CheckProductionCode(dto); if (!res) { throw new Exception("商品编码重复"); } _db.Productions.Update(dto); _db.SaveChanges(); //设置了AsNoTracking() 或 opt.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);后这样的方法就不能修改成功了。 //var eto = _db.Productions.Where(x => x.ProductionId == dto.ProductionId).FirstOrDefault(); //eto.ProductionName = dto.ProductionName; //_db.SaveChanges(); }