Entity Framework проглатывает SQL исключение / ошибка сервера (но ADO. NET нет) - PullRequest
0 голосов
/ 06 августа 2020

Проблема:

У меня есть хранимая процедура, и я могу успешно выполнить ее как с EF, так и с ADO. NET без проблем. Однако, если хранимая процедура выдает ошибку (с использованием RAISERROR или THROW), ее перехватывает только ADO. NET, а не EF. EF просто проглатывает исключение, а не перехватывает его. Сначала я использую код EF (не дизайнер).

Описание:

У меня есть базовая c хранимая процедура (выглядит большой из-за кода плиты котла) как следует (отрублено / написано от руки):

CREATE PROCEDURE SampleProc
    (@id BIGINT)
AS 
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY
        IF EXISTS (SELECT Id    
                   FROM SampleTable
                   WHERE Id = @id)
        BEGIN
            --;THROW 50000, 'row not found', 1
            RAISERROR ('row not found', -- Message text.  
                16, -- Severity.  
                1 -- State.  
            ); 
        END

        BEGIN TRANSACTION   
            DELETE FROM SampleTable
            WHERE Id  = @id
        COMMIT TRANSACTION

        SELECT 1 AS ReturnValue, CAST(@id AS VARCHAR(10)) AS [Message]
    END TRY
    BEGIN CATCH
        DECLARE @ErrorSeverity INT,
                @ErrorNumber   INT,
                @ErrorMessage NVARCHAR(4000),
                @ErrorState INT,
                @ErrorLine  INT,
                @ErrorProc NVARCHAR(200)

        SET @ErrorSeverity = ERROR_SEVERITY()
        SET @ErrorNumber   = ERROR_NUMBER()
        SET @ErrorMessage  = ERROR_MESSAGE()
        SET @ErrorState    = ERROR_STATE()
        SET @ErrorLine     = ERROR_LINE()
        SET @ErrorProc     = ERROR_PROCEDURE()
        SET @ErrorMessage  = 'Problem deleting from SampleTable.' + CHAR(13) + 'SQL Server Error Message: ' + CAST(@ErrorNumber AS VARCHAR(10)) + ' in procedure: ' + @ErrorProc + ' Line: ' + CAST(@ErrorLine AS VARCHAR(10)) + ' Error text: ' + @ErrorMessage
    
        IF @ErrorState  = 0
            SET @ErrorState = 1
    
        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRANSACTION
        END
        --;THROW 50000, @ErrorMessage, 1
        RAISERROR (@ErrorMessage , @ErrorSeverity, @ErrorState, @ErrorNumber)
    END CATCH
END

Я выполняю то же самое, используя ADO. NET следующим образом (работает без проблем и ловит RAISERROR/THROW из этой хранимой процедуры):

    var connection = new SqlConnection(ConnectionStringKey); //ADO.NET Connection

    try
    {
        using (var cmd = new SqlCommand("SampleProc", connection))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add(new SqlParameter("id", id));                    

            if (connection != null && connection.State == ConnectionState.Closed)
            {
                connection.Open();
            }

            using (var rdr = cmd.ExecuteReader())
            {
                if (rdr.Read())
                {
                    result.ReturnValue = (int)rdr["ReturnValue"];
                    result.Message = rdr["Message"].ToString();
                }
                else
                {
                    _logger.Warn($"WARNING: nothing is returned from SampleProc.");
                }
            }
        }                

        return result;
    }
    catch (Exception ex)
    {
        _logger.Error("ERROR:", ex);
        throw;
    }
    finally
    {
        if (connection != null && connection.State != ConnectionState.Closed)
        {
            try
            {
                connection.Close();
            }
            catch (Exception e) { }
        }
    }
}

Теперь при замене только соединения ADO. NET (в приведенном выше коде) на соединение EF исключение принимается (не перехватывает RAISERROR хранимой процедуры):

var connection = (SqlConnection)Database.Connection; //EF connection - rest of code stays same

Пытался использовать следующие два способа (используя EF), но безуспешно:

    Database.ExecuteSqlCommand(
            "exec SampleProc @Id",
            new SqlParameter("Id", id));
    
    result = Database.SqlQuery<StoredProcedureGenericResult>(
            "exec SampleProc @Id",
            new SqlParameter("Id", id))
        .First();

Кто-нибудь сталкивался с подобной проблемой?

...