C#与Entity Framework Core:捕获异常后无法更新Task记录
问题说明
我有两张数据库表,一张存储Task(任务),一张管理Widget(组件)。创建Task时其状态为"submitted",处理完成后会将状态更新为"complete"或"error"。
处理Task时,若尝试向Widget表插入无效数据(例如向非空字段插入null)会抛出异常,但此时无法将对应Task的状态更新为"error"。
注意:请勿评论数据一致性检查相关内容,示例代码为虚构,实际代码处理外部来源的可能存在不一致的数据,我仅想了解为何第一段代码在捕获异常后无法更新Task记录,而第二段代码可以正常运行。
第一段代码
public void createWidget(int taskID, int widgetID, int? widgetCount) { using (opxContext context = new opxContext()) { var task = context.tasks.Where(x => x.taskId == taskID).First(); try { var widget = context.Widget.Where(x => x.widgetId == widgetID).First(); Widget widget = new Widget { widgetID = widgetID, widgetCount = widgetCount }; context.Widget.add(widget); //若count为null会抛出异常,count不能为空 task.taskStatus = "complete"; context.SaveChanges(); Console.WriteLine("complete"); } catch (Exception e) { task.taskErrors = e.message; task.taskStatus = "error"; context.SaveChanges(); Console.WriteLine(e.message); //错误信息正常显示,但数据库中的task未更新 } } return; }
第二段代码
public void createWidget(int taskID, int widgetID, int? widgetCount) { try { using (opxContext context = new opxContext()) { var widget = context.Widget.Where(x => x.widgetId == widgetID).First(); Widget widget = new Widget { widgetID = widgetID, widgetCount = widgetCount }; context.Widget.add(widget); //若count为null会抛出异常,count不能为空 context.SaveChanges(); var task = context.tasks.Where(x => x.taskId == taskID).First(); task.taskStatus = "complete"; Console.WriteLine("complete"); } } catch (Exception e) { using (opxContext context = new opxContext()) { var task = context.tasks.Where(x => x.taskId == taskID).First(); task.taskErrors = e.message; task.taskStatus = "error"; context.SaveChanges(); Console.WriteLine(e.message); //错误信息正常显示,且数据库中的task成功更新 } } return; }
原因分析
第一段代码失败的核心原因
- DbContext进入失效状态:当
context.SaveChanges()在try块抛出异常后,ORM(如EF Core)会将当前DbContext标记为失效状态,此时上下文的变更追踪器已处于不一致状态,后续调用context.SaveChanges()不会执行任何数据库操作,甚至可能触发新异常。 - 无效变更未清除:try块中添加的无效Widget实体仍存在于上下文的变更追踪器中,catch块调用SaveChanges时,ORM会尝试提交所有未完成的变更(包括这个无效Widget),再次触发相同异常,导致Task的更新无法完成。
第二段代码能正常运行的原因
catch块中创建了全新的DbContext实例,这个新上下文没有之前的错误变更记录,仅追踪对Task的修改操作。调用SaveChanges时,只会提交Task的状态更新,不会涉及之前失败的Widget插入操作,因此能成功将Task状态更新为"error"。
内容的提问来源于stack exchange,提问作者Shawn Mesiatowsky
相关产品推荐
相关产品推荐

