2012-01-09 2 views
0

私のストアドプロシージャでは、Try-Catchを使用していて、Catchブロックでエラー処理プロシージャを呼び出してエラーログの詳細をErrorLogテーブルに記録し、エラーを再現します。トランザクションが中止された場合、私のエラーがストアドプロシージャを処理し、(scope.Completeが呼び出されることはありません)、SQL方法。トランザクション内で実行されるストアドプロシージャのエラーログテーブルへのエラー情報を試してみますか?

using(TransactionScope scope = new TransactionScope()) { 
    // execute stored procs 
    scope.Complete(); 
} 

私がいる問題を:私のC#コードで

は、私が使用して私のストアドプロシージャを実行していますsqlエラーは再実行されますが、TransactionのコンテキストにあるためErrorLogテーブルにエラーを記録することはできません。これを回避する方法はありますか?トランザクションがコミット不能な状態にあるときにデータを挿入できないことはすでに分かっています。トランザクションを終了してエラーをログに記録するにはどうすればよいですか?

TSQLコード:

BEGIN PROCEDURE [dbo].[usp_UpsertSomething] 
    @SomethingID BIGINT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    BEGIN TRY 
     -- do something 
    END TRY 
    BEGIN CATCH 
     EXEC dbo.cp_RethrowError 
     RETURN -1 
    END CATCH; 
END 

CREATE PROCEDURE [dbo].[usp_RethrowError] 
    @ErrorLogID [INT] = 0 OUTPUT -- Contains the ErrorLogID of the row inserted 
           -- by cp_RethrowError in the ErrorLog table. 
AS 
BEGIN 
    -- Return if there is no error information to retrieve. 
    IF ERROR_NUMBER() IS NULL 
     RETURN; 

    DECLARE 
     @ErrorMessage   VARCHAR(4000), 
     @FormattedErrorMessage VARCHAR(4000), 
     @ErrorNumber   INT, 
     @ErrorSeverity   INT, 
     @ErrorState    INT, 
     @ErrorLine    INT, 
     @ErrorProcedure   VARCHAR(200); 

    -- Assign variables to error-handling functions that 
    -- capture information for RAISERROR. 
    SELECT 
     @ErrorNumber = ERROR_NUMBER(), 
     @ErrorMessage = ERROR_MESSAGE(), 
     @ErrorSeverity = ERROR_SEVERITY(), 
     @ErrorState = ERROR_STATE(), 
     @ErrorLine = ERROR_LINE(), 
     @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-'); 

    -- Build the message string that will contain original 
    -- error information. 
    SELECT @FormattedErrorMessage = 
     'ErrorLogID %d, Error %d, Level %d, State %d, Procedure %s, ' + 
      'Line %d, Message: '+ @ErrorMessage; 

    BEGIN TRY 
     -- Data insertion/modification is not allowed when 
     -- a transaction is in an uncommittable state. 
     IF XACT_STATE() = -1 BEGIN 
      SET @ErrorLogID = 0; 
     END 
     ELSE BEGIN 
      INSERT [dbo].[ErrorLog] 
      (
       ErrorNumber, 
       ErrorSeverity, 
       ErrorState, 
       ErrorProcedure, 
       ErrorLine, 
       ErrorMessage 
      ) 
      VALUES 
      (
       @ErrorNumber, 
       @ErrorSeverity, 
       @ErrorState, 
       @ErrorProcedure, 
       @ErrorLine, 
       @ErrorMessage 
      ); 

      -- Pass back the ErrorLogID of the row inserted 
      SELECT @ErrorLogID = @@IDENTITY; 
     END 
    END TRY 
    BEGIN CATCH 
     PRINT 'An error occurred in stored procedure cp_RethrowError.'; 
    END CATCH 

    -- Raise an error: msg_str parameter of RAISERROR will contain 
    -- the original error information. 
    RAISERROR 
    (
     @FormattedErrorMessage, 
     @ErrorSeverity, 
     1, 
     @ErrorLogID,  -- parameter: ErrorLogID in ErrorLog table. 
     @ErrorNumber, -- parameter: original error number. 
     @ErrorSeverity, -- parameter: original error severity. 
     @ErrorState,  -- parameter: original error state. 
     @ErrorProcedure, -- parameter: original error procedure name. 
     @ErrorLine  -- parameter: original error line number. 
    ); 
END 

答えて

0

取引はオール・オア・ナッシングの契約なので、私が行っ望んだものを成し遂げるための唯一の方法は、私を呼び出す前に、Catchブロックの内部でのROLLBACK TRANSACTIONを呼び出すことですエラー処理呼び出し。

私のログにはエラーが記録されますが、私の.Net catchブロックではSQLからの苦情があります: "EXECUTE後のトランザクション数は、COMMITまたはROLLBACK TRANSACTION文が見つからないことを示します。カウント= 1、現在のカウント= 0 "

私はそれと一緒に暮らすことができます!

0

エラーログエントリを最初にテーブル変数(実際のログテーブルと同じ構造にする必要があります)に入れることもできます。ロールバックはテーブル変数をクリアしません。最後に、テーブル変数の内容を実際のログテーブルに挿入するだけです。

私はそれを試していないが、うまくいく可能性があります。 自律型トランザクションのような機能はSQL Serverにはまだありません(Oracleはすでに持っています)。自律的なトランザクションで行うことは、メイントランザクションとは独立しています。これはまさにエラー・ロギングの場合に必要なものです。特に、トランザクションがロールバックされても、何が起こったのかを知りたい場合は特にそうです。

0

これはシーケンシングの問題です。エラーハンドラのトランザクション数を確認してください。 手順: 1.最初に@variablesまたは@tableに元のエラー情報を取得します。 2.トランザクション数を確認し、0より大きい場合はロールバックします。 3.手順1で収集したばかりのエラー情報を挿入します。 完了しました。

関連する問題