Проблема:
У меня есть хранимая процедура, и я могу успешно выполнить ее как с 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();
Кто-нибудь сталкивался с подобной проблемой?