DbContext SaveChanges未更新数据库:HTML表单修改MaxInvalidPasswordAttempts失效问题
解决EF中修改实体属性后SaveChanges()不更新数据库的问题
我最近碰到过一模一样的坑!调试时明明看到b.MaxInvalidPasswordAttempts已经被赋了新值,但调用db.SaveChanges()之后,数据库里的数据纹丝不动,当时差点挠破头。先看看你的代码:
public ActionResult Submit(config asp) { using(var db=new DB()) { Operation op = new Operation(); var result = op.Fetch(); foreach (var b in result) { b.MaxInvalidPasswordAttempts = asp.MaxInvalidPasswordAttempts; } try { db.SaveChanges(); } catch (Exception e) { return Content(e.Message); } } return ... }
问题根源
核心问题出在实体的跟踪状态上:你通过op.Fetch()拿到的实体,根本不在当前db上下文的跟踪范围内!EF只有对自己上下文实例跟踪的实体做修改时,才会在SaveChanges()时生成对应的数据库更新语句。如果Fetch()方法是用另一个上下文实例或者非EF方式查询的,那这些实体就是“游离状态”,当前的db完全不知道它们被修改了,自然不会去更新数据库。
两种解决方案
方案一:用当前上下文直接查询实体
最简单的办法就是让实体从一开始就处于当前db的跟踪中,直接用当前上下文查询数据:
public ActionResult Submit(config asp) { using(var db=new DB()) { // 直接通过当前db上下文获取实体,自动处于跟踪状态 var result = db.Operations.ToList(); foreach (var b in result) { b.MaxInvalidPasswordAttempts = asp.MaxInvalidPasswordAttempts; } try { db.SaveChanges(); } catch (Exception e) { return Content(e.Message); } } return ... }
方案二:手动附加实体并标记修改
如果没办法修改Fetch()的实现,那就把游离的实体附加到当前上下文,并手动标记它(或指定属性)为已修改:
public ActionResult Submit(config asp) { using(var db=new DB()) { Operation op = new Operation(); var result = op.Fetch(); foreach (var b in result) { // 附加实体到当前上下文,标记为已修改 db.Entry(b).State = EntityState.Modified; // 也可以只标记特定属性,更高效 // db.Entry(b).Property(x => x.MaxInvalidPasswordAttempts).IsModified = true; b.MaxInvalidPasswordAttempts = asp.MaxInvalidPasswordAttempts; } try { db.SaveChanges(); } catch (Exception e) { return Content(e.Message); } } return ... }
额外提醒
还要确认你的Operation实体类已经正确配置了主键——如果EF找不到实体的唯一标识,就算附加了也没法正确生成更新语句哦!
内容的提问来源于stack exchange,提问作者NoOneJr
相关产品推荐
相关产品推荐

