2011-11-29 114 views
1

我有我從C#做調用帶有事務的存儲過程:TSQL嘗試捕捉交易錯誤處理,交易數量不匹配

using (var dbContext = PowerToolsDatabase.GetDataContext()) 
{ 
    dbContext.Connection.Open(); 
    using (dbContext.Transaction = dbContext.Connection.BeginTransaction(System.Data.IsolationLevel.Serializable)) 
    { 
     foreach (var element in package.AddOrUpdateElements) 
     { 
      dbContext.usp_Element_Commit(/* args */); 
     } 

     dbContext.Transaction.Commit(); 
    } 
} 

而且在存儲過程有一個嘗試捕捉和RAISERROR內即在某些情況下執行的嘗試部分

BEGIN TRY 
    BEGIN TRANSACTION 
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

    -- Perform Name Uniqueness check (for new) 
    IF EXISTS (SELECT PK.identifier --...) 
    BEGIN 

     RAISERROR(60000, 16, 1, 'dbo.usp_Element_Commit', 'Supplied Element Name (for new Element) already exists') 

     RETURN 

    END 

    -- Do stuff   

    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 

    IF XACT_STATE() <> 0 
    BEGIN 
     ROLLBACK TRANSACTION; 
    END 

    DECLARE @ErrorMessage NVARCHAR(4000); 
    DECLARE @ErrorSeverity INT; 
    DECLARE @ErrorState INT; 

    SELECT 
     @ErrorMessage = 'dbo.usp_Element_Commit -- ' + ERROR_MESSAGE(), 
     @ErrorSeverity = ERROR_SEVERITY(), 
     @ErrorState = ERROR_STATE(); 

    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState); 

END CATCH; 

當我運行,並擊中了存儲過程的Try段內的RAISERROR我得到以下多個錯誤:

dbo.usp_Element_Commit -- Supplied Element Name (for new Element) already exists 
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0. 
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0. 

什麼是推薦的方式來處理錯誤和跳轉到catch塊而不搞亂外部事務?

另外,如果我從catch塊在存儲過程中刪除回滾然後我得到同樣的交易計數信息與先前計= 1,當前計數= 2

+0

當出現錯誤時,您的C#如何跳過COMMIT? –

+0

@KM從dbContext.usp_Element_Commit調用中拋出一個SqlException,所以它將跳轉到封閉使用塊中的dispose,該塊使用c#事務調用Rollback – BrandonAGr

+1

@JNK一次回滾回滾所有內容。 WHILE XACT_STATE()<> 0沒有意義。你可以嘗試一下,看看自己。 –

回答

1

我改變存儲過程以follow this pattern使用一個保存的點或交易取決於是否已有交易。它現在按預期工作。

BEGIN TRY 
    declare @trancount int = @@trancount 
    if @trancount = 0 
     begin transaction 
    else 
     save transaction usp_element_commit_transaction; 

    set transaction isolation level serializable 

    -- Perform Name Uniqueness check (for new) 
    IF EXISTS (SELECT PK.identifier --...) 
    BEGIN 

     RAISERROR(60000, 16, 1, 'dbo.usp_Element_Commit', 'Supplied Element Name (for new Element) already exists') 

     RETURN 

    END 

    -- Do stuff   

    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 

    declare @xstate int = xact_state() 
    if @xstate = -1 
     rollback 
    else if @xstate = 1 and @trancount = 0 
     rollback 
    else if @xstate = 1 and @trancount > 0 
     rollback transaction usp_element_commit_transaction; 

    DECLARE @ErrorMessage NVARCHAR(4000); 
    DECLARE @ErrorSeverity INT; 
    DECLARE @ErrorState INT; 

    SELECT 
     @ErrorMessage = 'dbo.usp_Element_Commit -- ' + ERROR_MESSAGE(), 
     @ErrorSeverity = ERROR_SEVERITY(), 
     @ErrorState = ERROR_STATE(); 

    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState); 

END CATCH;