私のtryブロックで発生したSQLサーバーで同じ例外を再スローしたいです。私は同じメッセージを投げることができますが、同じエラーを投げたいです。
_BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Tags.tblDomain
(DomainName, SubDomainId, DomainCode, Description)
VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
declare @severity int;
declare @state int;
select @severity=error_severity(), @state=error_state();
RAISERROR(@@Error,@ErrorSeverity,@state);
ROLLBACK TRANSACTION
END CATCH
_
RAISERROR(@@Error, @ErrorSeverity, @state);
この行にはエラーが表示されますが、そのような機能が必要です。これにより、エラー番号50000のエラーが発生しますが、_@@error
_を渡そうとしているerron番号がスローされるようにします。
フロントエンドでこのエラーをキャプチャしません
つまり.
_catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}
_
この機能が欲しい。 raiseerrorを使用して達成することはできません。バックエンドでカスタムエラーメッセージを表示したくありません。
RAISEERRORは、キャッチでスローされるErrorNoを渡すと、以下のエラーを返す必要があります
_Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,
_行14一意キー制約 'UK_DomainCode'の違反。オブジェクト 'Tags.tblDomain'に重複キーを挿入できません。ステートメントは終了されました。
編集:
ストアドプロシージャに実行する必要がある複数のクエリが含まれていることを考慮して、フロントエンドで例外を処理する場合、try catchブロックを使用しない場合の欠点は何ですか
エラーが発生した場合に一連のステートメントをロールバックし、エラーメッセージを報告する完全に機能するクリーンなコードサンプルを次に示します。
begin try
begin transaction;
...
commit transaction;
end try
begin catch
declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
rollback transaction;
raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
SQL 2012では、throwステートメントが導入されています。
http://msdn.Microsoft.com/en-us/library/ee677615.aspx
パラメーターなしでTHROWステートメントを指定する場合、CATCHブロック内に表示する必要があります。これにより、キャッチされた例外が発生します。
BEGIN TRY
BEGIN TRANSACTION
...
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
THROW
END CATCH
CATCHブロック内で再スローします(SQL2012以前のコード。SQL2012以降ではTHROWステートメントを使用します)。
DECLARE
@ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
@ErrorNumber int = ERROR_NUMBER(),
@ErrorSeverity int = ERROR_SEVERITY(),
@ErrorState int = ERROR_STATE(),
@ErrorLine int = ERROR_LINE(),
@ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
あなたの選択は次のとおりだと思います:
ある時点で、SQLはおそらくリレイズコマンド、または特定のエラーのみをキャッチする機能を導入します。しかし今のところ、回避策を使用してください。ごめんなさい。
できない:50000未満のエラーをスローできるのはエンジンだけです。できることは、looksのような例外をスローすることだけです...
ここの質問者は、クライアント側のトランザクションを使用して、彼が望んでいたことを実行しましたが、これはちょっとばかげていると思います...
まだ2012年に移行していない場合、元のエラーコードのバブリングアップを実装する1つの方法は、catchブロックから(再)スローしている例外のテキストメッセージ部分を使用することです。キャッチャーブロックで解析する呼び出し元コードのXMLテキストなど、何らかの構造を含めることができることに注意してください。
エラーが発生した後にストアドプロシージャの実行を停止し、呼び出し元のプログラムにエラーをバブルバックする方法は、このコードでエラーをスローする可能性のある各ステートメントに従うことです。
If @@ERROR > 0
Return
ストアドプロシージャの実行がエラーの後も継続できることを知って驚いた-これを認識しないと、バグを追跡するのが困難になる可能性がある。
このタイプのエラー処理は(.Netより前の)Visual Basic 6に匹敵します。SQLServer 2012のThrowコマンドを楽しみにしています。
OK、これは回避策です... :-)
DECLARE @Error_Number INT
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish')
/* Column 'Name' has unique constraint on it*/
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER()
--RAISERROR (@ErrorMessage,@Severity,@State)
ROLLBACK TRAN
END CATCH
Catchブロックに注意すると、エラーが発生するのではなく、実際のエラー番号が返されます(トランザクションもロールバックされます)。 .NETコードで、例外をキャッチする代わりに、ExecuteScalar()を使用すると、実際のエラー番号を取得し、適切な番号を表示します。
int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
MessageBox.Show("Some message");
}
お役に立てれば、
編集:-注:影響を受けるレコードの数を取得してExecuteNonQueryを使用しようとすると、上記の解決策が機能しない場合があります。 。
トランザクション内でSQLステートメントを実行し、コードにエラーをフィードする場合、これらのシナリオのラッパーストアドプロシージャを作成することもできます。
CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
@SQL nvarchar(max)
)
AS
SET NOCOUNT ON
BEGIN TRY
BEGIN TRANSACTION
EXEC(@SQL)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
ROLLBACK TRANSACTION
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH
GO
-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'