为什么 dapper 查询会失败而 ado 调用却不会?

Why does a dapper query fail and a ado call not?

在 netcore 5 C# 中,我在应用程序启动时检查数据库是否为最新版本,如果不是,则根据特定客户安装的版本自动更新(并为每个客户执行特定操作)。

我正在重构并尝试查看是否可以用 Dapper 调用替换当前的 sql 执行调用但失败了:

一个。例如,我在一个字符串中有这样一段 sql:

SET NUMERIC_ROUNDABORT OFF
SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON SET DATEFORMAT YMD SET XACT_ABORT ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRANSACTION

DECLARE @items AS CURSOR
DECLARE @item AS nvarchar(250)

SET @items = CURSOR FOR
    SELECT
        N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(t.parent_object_id)) +  N'.' + QUOTENAME(OBJECT_NAME(t.parent_object_id)) + '  DROP CONSTRAINT ' +  QUOTENAME(t.name) +  N';'

    FROM
        [sys].[check_constraints] AS t
    WHERE
        t.is_ms_shipped = 0

    OPEN @items FETCH NEXT FROM @items INTO @item WHILE @@FETCH_STATUS = 0

BEGIN
    EXEC (@item)

    FETCH NEXT FROM @items INTO @item

END

CLOSE @items

DEALLOCATE @items 

COMMIT TRANSACTION

b。我 运行 这(在交易中)与 Dapper:

public IDbConnection DbConnection
    {
        get
        {
            return new SqlConnection(_connectionstring);
        }
    }

using IDbConnection db = DbConnection;
await db.ExecuteAsync(statement)

失败并显示“System.PlatformNotSupportedException:该平台不支持分布式事务。”

c。当我将 dapper 调用替换为:

string connectionString = _context.Database.GetDbConnection().ConnectionString;
SqlConnection _connection = new SqlConnection(connectionString);
await _connection.ExecuteCommandAsync(statement).ConfigureAwait(false);

它 运行 很好(以及之后的所有其他 sql 语句)

围绕它的交易是:

using (TransactionScope scope
                        = new TransactionScope(TransactionScopeOption.Required, System.TimeSpan.FromMinutes(10),
                                       TransactionScopeAsyncFlowOption.Enabled))
                    {
  // a loop with hundreds of sql files and corresponding calls
  // to execute
}

(我知道 https://github.com/dotnet/runtime/issues/19318

应要求提供完整的堆栈跟踪

System.PlatformNotSupportedException: This platform does not support distributed transactions.
   at System.Transactions.Distributed.DistributedTransactionManager.GetDistributedTransactionFromTransmitterPropagationToken(Byte[] propagationToken)
   at System.Transactions.TransactionInterop.GetDistributedTransactionFromTransmitterPropagationToken(Byte[] propagationToken)
   at System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)
   at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)
   at System.Transactions.EnlistableStates.Promote(InternalTransaction tx)
   at System.Transactions.Transaction.Promote()
   at System.Transactions.TransactionInterop.ConvertToDistributedTransaction(Transaction transaction)
   at System.Transactions.TransactionInterop.GetExportCookie(Transaction transaction, Byte[] whereabouts)
   at System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction transaction, Byte[] whereAbouts)
   at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.PrepareConnection(DbConnection owningObject, DbConnectionInternal obj, Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()
--- End of stack trace from previous location ---
   at Dapper.SqlMapper.ExecuteImplAsync(IDbConnection cnn, CommandDefinition command, Object param) in /_/Dapper/SqlMapper.Async.cs:line 645

根据我在评论中的想法,没有改变属性,您可以尝试添加

db.Open();

await db.OpenAsync().ConfigureAwait(false);

到您现有的代码中,假设差异是连接打开的次数。


猜测,但我想知道异常是否纯粹是由 属性 getter 每次返回一个新连接引起的。这意味着您可能涉及多个连接,这(当与 TransactionScope 结合使用时)可能会导致不好的事情。也许只是:

private IDbConnection _db;
public IDbConnection DbConnection
   => _db ?? CreateOpenConnection();
private IDbConnection CreateOpenConnection()
{
    if (_db is null)
    {
        _db = new SqlConnection(_connectionstring);
        _db.Open();
    }
    return _db;
}