首页 > 解决方案 > 将 TransactionScope 与存储过程事务一起使用不起作用

问题描述

据我了解,在存储过程中TransactionScope包装 T-SQL 时,C# 仍然可以工作。BEGIN / COMMIT TRANSACTION

我有以下 C# 方法,它EF Save首先执行,然后调用具有自己的事务的存储过程,然后通过 HTTP 调用外部服务

public async Task DoSomething(MyDto dto)
{
        using (var scope = new TransactionScope())
        {
            //Save First
            var myEntity = await _dbContext.MyEntity.Where(x=>x.Id == dto.Id).SingleOtDefaultAsync();

            // Assign properties here from dto to MyEntity and then save entity             
            await _dbContext.SaveChangesAsync();

            // call stored procedure that has its own transaction
            _dbContext.prcDoExtraWork(dto.Id);

            // call external service using Http             
            await _httpClient.PostAsync(url,somecontent)

            scope.Complete();
        }
}

存储过程:

CREATE PROCEDURE [dbo].[prcDoExtraWork]
    @ID INT 
AS
BEGIN
    SET NOCOUNT ON;
    SET ANSI_WARNINGS ON;
    SET XACT_ABORT ON;     

    BEGIN TRY
        BEGIN TRANSACTION
            // modify data and  inserts records into tables
        COMMIT TRANSACTION

        SELECT 1 AS `Result`
    END TRY
    BEGIN CATCH
        IF (XACT_STATE() <> 0)
        BEGIN       
            ROLLBACK TRANSACTION

            IF @ErrorMessage IS NULL
            BEGIN
                SET @ProcName = ERROR_PROCEDURE();
                SET @ErrorMessage = ERROR_MESSAGE();
                SET @ErrorNumber = ERROR_NUMBER();
                SET @ErrorSeverity = ERROR_SEVERITY();
                SET @ErrorState = ERROR_STATE();
            END

            EXEC prcErrorHandler @ProcName = @ProcName, 
                                 @ErrorMessage = @ErrorMessage, 
                                 @ErrorSeverity = @ErrorSeverity,
                                 @ErrorState = @ErrorState, 
                                 @ErrorNumber = @ErrorNumber

            SELECT 0 AS `Result`
        END
    END CATCH

    SET XACT_ABORT OFF;
END

问题1:通过http调用外部服务失败,我的期望是存储过程插入或修改的任何记录都会回滚。

然而,这并没有发生。我仍然在数据库中看到新记录

第 2 期

为了解决上面的错误,我必须启用 TransactionScopeAsyncFlowOption,因为我使用的是异步方法

using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
    {

     // do your stuff
     scope.complete();
   }

但是现在在 scope.complete() 我得到错误

无法执行事务操作,因为有处理此事务的待处理请求

System.Transactions.TransactionAbortedException:事务已中止。---> System.Data.SqlClient.SqlException:事务操作无法执行,因为有待处理的请求正在处理此事务。在 System.Data.SqlClient.SqlConnection.OnError(SqlException 异常,布尔 breakConnection,Action`1 wrapCloseInAction)在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,布尔 callerHasConnectionLock,布尔 asyncClose)在 System.Data.SqlClient.TdsParser System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,SqlCommand cmdHandler,

标签: sql-serverentity-frameworkado.nettransactionscopemsdtc

解决方案


我想我找到了。
我通过启用解决了第一个问题,TransactionScopeAsyncFlowOption因为我使用的是异步方法

        using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
        {

         // do your stuff
         scope.complete();
       }

第二个问题
存储过程根据成功或错误返回 1 或 0。C# 代码不关心返回结果的值,但是我没有评估存储过程的返回结果。所以要解决我必须调用'SingleOrDefault`

_dbContext.prcDoExtraWork(dto.Id).SingleOrDefault()


推荐阅读