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

为什么.NET 5中Dapper执行SQL失败但原生ADO调用正常?

错误原因

你遇到的报错本质是事务提升为分布式事务后平台不支持,触发条件和对应逻辑如下:

  • 外层使用了TransactionScope创建环境事务,当同一个环境事务范围内打开2个及以上的SqlConnection连接时,.NET的事务管理器会自动将本地事务升级为分布式事务。
  • .NET Core/.NET 5+ 仅在Windows平台对MSDTC分布式事务有有限支持,非Windows平台会直接抛出PlatformNotSupportedException,和你提供的错误栈完全匹配。
  • 你之前的Dapper写法每次执行SQL都new了新的SqlConnection实例,循环执行数百条SQL时会打开多个连接,直接触发事务升级;而复用EF上下文的DbConnection时全程只有一个连接实例,不会触发升级所以运行正常。
解决方案

方案1:复用同一连接实例(最推荐,改动最小)

在整个TransactionScope生命周期内只初始化一个SqlConnection实例,所有SQL执行都复用该连接,避免出现多连接触发事务升级,示例代码:

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(10), TransactionScopeAsyncFlowOption.Enabled))
using (IDbConnection db = new SqlConnection(_connectionstring))
{
    // 循环执行所有SQL语句,全程复用当前db连接
    foreach (var sqlStatement in allSqlStatements)
    {
        await db.ExecuteAsync(sqlStatement);
    }
    scope.Complete();
}

注意:如果你的SQL语句中自带BEGIN TRANSACTION/COMMIT TRANSACTION逻辑,建议去掉,避免和外层的TransactionScope产生嵌套事务冲突。

方案2:使用Dapper原生本地事务管理

完全弃用TransactionScope,直接通过数据库连接开启本地事务,所有Dapper操作都传入该事务实例,从根源上避免分布式事务触发:

using (IDbConnection db = new SqlConnection(_connectionstring))
{
    db.Open();
    using (var transaction = db.BeginTransaction())
    {
        try
        {
            foreach (var sqlStatement in allSqlStatements)
            {
                await db.ExecuteAsync(sqlStatement, transaction: transaction);
            }
            transaction.Commit();
        }
        catch
        {
            transaction.Rollback();
            throw;
        }
    }
}

方案3:关闭连接自动事务登记(不推荐)

在数据库连接字符串中添加Enlist=false参数,强制连接不自动加入当前环境事务,不会触发事务升级,但该方案下TransactionScope无法管控数据库操作的事务一致性,需要自行管理事务边界。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 12:27:05