EF使用FirstOrDefault后SaveChanges返回2 Sal表产生重复记录问题
问题说明
实现用户记录更新功能时,通过FirstOrDefault()获取匹配UserName的第一条记录q后调用SaveChanges()方法,出现以下异常表现:
- 已确认数据库中仅存在1条匹配的待更新记录
SaveChanges()返回的受影响行数success为2,不符合预期值1- 执行完成后Sal表中出现2条重复记录
需要调整查询与更新逻辑,正确完成单条记录的更新操作。
原有问题代码
public static bool UpdateUser(User user) { try { var q = db.Users.Where(x => x.UserName == user.UserName).FirstOrDefault(); if (q != null) { q.Password = user.Password; db.Users.Update(user); int success = db.SaveChanges(); if (success == 1) { return true; } else { return false; } } return false; } catch (Exception ex) { throw ex; } }
问题根因
问题和FirstOrDefault()查询逻辑无关,是重复提交实体更新导致的:
- 调用
FirstOrDefault()查询到的实体q会被EF Core的变更追踪器自动跟踪,修改q.Password属性后,EF已经自动将q标记为待更新状态 - 后续调用
db.Users.Update(user)时,传入的是方法参数中的user对象,该对象未被当前上下文追踪,EF会将其作为独立实体附加到上下文并标记为待写入状态。如果user对象的主键值未被EF正确识别,EF会将其判定为新记录执行插入操作 - 执行
SaveChanges()时,EF会同时处理两个实体的写入操作:一条是跟踪到的q的更新,一条是user的插入/更新,因此返回受影响行数为2,同时出现重复数据。
修复方案
保留原有先查询再更新的逻辑即可,删除多余的db.Users.Update(user)调用,EF变更追踪器会自动感知已查询实体的属性修改,SaveChanges()只会生成单条更新SQL,返回受影响行数为1。
修复后代码如下:
public static bool UpdateUser(User user) { try { var q = db.Users.FirstOrDefault(x => x.UserName == user.UserName); if (q != null) { q.Password = user.Password; // 移除多余的手动Update调用,EF自动跟踪已查询实体的属性变更 int success = db.SaveChanges(); return success == 1; } return false; } catch (Exception) { throw; // 注意不要使用throw ex,会丢失原始异常调用堆栈,直接throw即可保留完整异常信息 } }
补充说明:如果要使用
db.Users.Update()方法做离线实体更新,不需要提前查询数据库,直接传入主键匹配的实体调用Update再SaveChanges即可,不要同时混用跟踪查询修改+手动Update的写法,避免重复提交变更。
内容的提问来源于stack exchange,提问作者farzadini
相关产品推荐
相关产品推荐

