You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

原因分析

第一段代码失败的核心原因

  1. DbContext进入失效状态:当context.SaveChanges()在try块抛出异常后,ORM(如EF Core)会将当前DbContext标记为失效状态,此时上下文的变更追踪器已处于不一致状态,后续调用context.SaveChanges()不会执行任何数据库操作,甚至可能触发新异常。
  2. 无效变更未清除:try块中添加的无效Widget实体仍存在于上下文的变更追踪器中,catch块调用SaveChanges时,ORM会尝试提交所有未完成的变更(包括这个无效Widget),再次触发相同异常,导致Task的更新无法完成。

第二段代码能正常运行的原因

catch块中创建了全新的DbContext实例,这个新上下文没有之前的错误变更记录,仅追踪对Task的修改操作。调用SaveChanges时,只会提交Task的状态更新,不会涉及之前失败的Widget插入操作,因此能成功将Task状态更新为"error"。


内容的提问来源于stack exchange,提问作者Shawn Mesiatowsky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 21:42:01