c# - 为什么 dapper 查询会失败而 ado 调用不会失败?

标签 c# entity-framework dapper asp.net-core-5.0

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

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

a.例如,我在字符串中有这段 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.当我将简洁的调用替换为:

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

关于c# - 为什么 dapper 查询会失败而 ado 调用不会失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69059732/

相关文章:

c# - 如何将命令绑定(bind)到祖先数据上下文? WPF::MVVM

asp.net - 如何在gridview中将日期显示为仅日期而不是日期时间?

c# - 使用 SqlConnection() 和连接字符串连接到数据库安全吗?

c# - 在 .NET Web API 中重用与 Dapper 的数据库连接

c# - 有人可以解释这行代码吗?

c# - CommandInvokationFailure : Unable to merge android manifests. 有关详细信息,请参阅控制台。我已经对项目中的所有 list 文件进行了更改

c# - ASP.NET MVC5 Entity Framework 应用程序中的单一上下文

asp.net - Dapper.net交易问题

c# - 在与速度相关的时间间隔内播放滴答声的最有效方法?

entity-framework - 为什么使用自定义 DbInitializer 的 EntityFramework 6.1 索引不起作用?