일부 저장 프로 시저를 체인화하고 있으며 오류 처리가 제대로 작동하는 데 문제가 있습니다. 이러한 저장 프로 시저 중 일부는 오래 실행되므로 저장 프로 시저 내에서 SqlInfoMessageEventHandler
및 코드 (예 : RAISERROR('whatever',10,1) WITH NOWAIT
)를 사용하여 작업 진행률을 사용자에게보고했습니다. 이를 위해 cmd.ExecuteNonQuery()를 사용할 수없고 대신 cmd.ExecuteReader()를 사용해야한다는 내용을 읽었습니다. 나는 이것을 시도해 보았다. ExecuteNonQuery에서 메시지가 표시되지 않습니다.ExecuteReader를 사용하여 SQL Server 체인 된 저장된 proc을 ErrorHandling
내가 발견 한 문제는 ExecuteReader를 사용할 때 저장된 proc이 오류를 throw하면 무시됩니다. 이것은 내 .NET 응용 프로그램을 try 블록에서 호출하고 저장 프로 시저에 SELECT 1/0과 같은 오류가 발생하면 실행이 catch 블록에 입력되지 않고 내 트랜잭션을 커밋한다는 것을 의미합니다. 예를 들면 다음과 같습니다.
일부 .NET 코드 등으로IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TempTstTbl]') AND type in (N'U'))
DROP TABLE [dbo].[TempTstTbl]
CREATE TABLE [dbo].[TempTstTbl] (
Step INT,
Val VARCHAR(50)
)
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Child]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[Child]
GO
CREATE PROCEDURE [dbo].[Child]
AS
BEGIN
BEGIN TRY
INSERT INTO [dbo].[TempTstTbl] (Step, Val) VALUES (1, 'FROM CHILD BEFORE FAULT')
SELECT 1/0
--RAISERROR ('This should really fail', 16, 2)
INSERT INTO [dbo].[TempTstTbl] (Step, Val) VALUES (2, 'FROM CHILD AFTER FAULT')
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
END CATCH;
END
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Parent]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[Parent]
GO
CREATE PROCEDURE [dbo].[Parent]
AS
BEGIN
BEGIN TRY
INSERT INTO [dbo].[TempTstTbl] (Step, Val) VALUES (1, 'FROM PARENT BEFORE CHILD')
Exec [dbo].[Child]
INSERT INTO [dbo].[TempTstTbl] (Step, Val) VALUES (2, 'FROM PARENT AFTER CHILD')
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
END CATCH;
END
GO
EXEC [dbo].[Parent]
SELECT * FROM [dbo].[TempTstTbl]
;
private void button4_Click(object sender, EventArgs e)
{
using (SqlConnection conn = new SqlConnection(@"Data Source=XPDEVVM\XPDEV;Initial Catalog=MyTest;Integrated Security=SSPI;"))
{
conn.Open();
using (SqlTransaction trans = conn.BeginTransaction())
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.Transaction = trans;
cmd.CommandText = "[cfg].[Parent]";
cmd.CommandType = CommandType.StoredProcedure;
try
{
-- cmd.ExecuteReader(); -- Using this instead of ExecuteNonQuery means the divide by 0 error in the stored proc is ignored, and everything is committed :(
cmd.ExecuteNonQuery();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
}
}
}
}
}
사람이 내 저장된 프로 시저에서 내 진행 메시지를 얻을 수있는 방법에 대한 아이디어를 가지고 있지만, 여전히 오류가 저장 프로 시저에서 발생하는 경우 .NET 예외를 잡을 수 있습니까?