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

使用System.Transactions在EF中批量更新多行报错,求解决方案

解决EF Core中SqlServerRetryingExecutionStrategy不支持手动事务的问题

这个错误的核心原因是:EF Core为SQL Server默认配置的SqlServerRetryingExecutionStrategy(重试执行策略)需要完全掌控事务的生命周期——它设计用来自动处理SQL Server的可重试错误(比如死锁、临时连接失败),但你手动调用BeginTransaction()创建的事务不在它的管理范围内,所以会触发这个报错。

正确的解决方案:用执行策略包裹整个事务逻辑

我们需要使用EF提供的CreateExecutionStrategy()方法获取重试策略,然后把所有需要在事务中执行的操作放到这个策略的Execute方法里,让它来管理整个事务的重试和提交/回滚逻辑。

修改后的代码如下:

public void Update(List<PortfolioCompanyLinkModel> records)
{
    // 获取SQL Server的重试执行策略
    var executionStrategy = _context.Database.CreateExecutionStrategy();

    // 让执行策略包裹整个事务操作,确保可重试
    executionStrategy.Execute(() =>
    {
        using (var transaction = _context.Database.BeginTransaction())
        {
            try
            {
                foreach (var item in records)
                {
                    var portfolioCompanyLink = _context.PortfolioCompanyLink.FirstOrDefault(p => p.Id == item.Id);
                    // 增加null判断,避免空引用异常
                    if (portfolioCompanyLink == null)
                    {
                        continue; // 或者根据业务逻辑抛出异常
                    }

                    portfolioCompanyLink.ModifiedBy = _loggedInUser;
                    portfolioCompanyLink.ModifiedOn = DateTime.UtcNow;
                    portfolioCompanyLink.URL = item.URL;
                }

                // 统一提交所有更改,比循环内多次SaveChanges更高效
                _context.SaveChanges();
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
                // 重新抛出异常,让执行策略判断是否需要重试(比如死锁这类可重试错误)
                throw;
            }
        }
    });
}

关键细节说明:

  • 重试策略的作用:Execute方法会将内部的所有逻辑视为一个原子单元,如果遇到SQL Server的可重试错误,它会自动回滚当前事务,然后重新执行整个逻辑,直到成功或达到重试上限。
  • 优化SaveChanges调用:原来的代码在循环内每次调用SaveChanges会产生多次数据库请求,改成最后统一调用一次,大幅提升性能,同时确保所有更改在同一个事务中提交。
  • 空引用防护:FirstOrDefault可能返回null,必须增加判断,避免后续赋值时抛出空引用异常。
  • 异常处理:捕获异常回滚事务后,一定要重新抛出异常,这样执行策略才能识别是否是可重试的错误,进而决定是否重试。

如果你确实不需要重试策略(不推荐,因为SQL Server的死锁等问题很常见),也可以在DbContext配置中禁用它,但这是下策:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer("YourConnectionString", builder =>
            builder.ExecutionStrategy(dependencies => new DefaultExecutionStrategy(dependencies)));
}

不过强烈建议保留重试策略,用第一种方法解决问题,这样你的代码能更好地应对SQL Server的临时故障。

内容的提问来源于stack exchange,提问作者Harsha Mullangi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:08:38