いくつかのパラメーターの検証を行うストアドプロシージャがあり、パラメーターが無効な場合、失敗して実行を停止する必要があります。
エラーチェックの最初の方法は次のとおりです。
create proc spBaz
(
@fooInt int = 0,
@fooString varchar(10) = null,
@barInt int = 0,
@barString varchar(10) = null
)
as
begin
if (@fooInt = 0 and (@fooString is null or @fooString = ''))
raiserror('invalid parameter: foo', 18, 0)
if (@barInt = 0 and (@barString is null or @barString = ''))
raiserror('invalid parameter: bar', 18, 0)
print 'validation succeeded'
-- do some work
end
重大度18は実行を停止せず、エラーメッセージと共に「検証成功」が出力されるため、これはうまくいきませんでした。
すべてのレイサーの後に単にリターンを追加できることは知っていますが、これは私にはちょっと醜いように見えます:
if (@fooInt = 0 and (@fooString is null or @fooString = ''))
begin
raiserror('invalid parameter: foo', 18, 0)
return
end
...
print 'validation succeeded'
-- do some work
重大度が11以上のエラーはtry/catchブロック内でキャッチされるため、テストした別のアプローチは、そのようなtry/catchブロック内にエラーチェックをカプセル化することでした。問題は、エラーが飲み込まれ、クライアントにまったく送信されないことでした。だから私はいくつかの研究をして、 rethrow エラーへの方法を見つけました:
begin try
if (@fooInt = 0 and (@fooString is null or @fooString = ''))
raiserror('invalid parameter: foo', 18, 0)
...
end try
begin catch
exec usp_RethrowError
return
end catch
print 'validation succeeded'
-- do some work
私はまだこのアプローチに満足していないので、私はあなたに尋ねています:
パラメーター検証はどのように見えますか?この種のチェックを行うための「ベストプラクティス」はありますか?
これを行うための単一の「正しい」方法があるとは思いません。
私自身の設定は2番目の例に似ていますが、各パラメーターの個別の検証ステップと、より明示的なエラーメッセージが含まれます。
あなたが言うように、それは少し面倒で醜いですが、コードの意図はそれを読んでいる誰にとっても明白であり、それは仕事を成し遂げます。
IF (ISNULL(@fooInt, 0) = 0)
BEGIN
RAISERROR('Invalid parameter: @fooInt cannot be NULL or zero', 18, 0)
RETURN
END
IF (ISNULL(@fooString, '') = '')
BEGIN
RAISERROR('Invalid parameter: @fooString cannot be NULL or empty', 18, 0)
RETURN
END
この回答の履歴からわかるように、私はこの質問に従い、回答を受け入れ、基本的に2番目のアプローチと同じソリューションを「発明」しました。
コーディングにあまりにも多くの時間を費やしているため、人生のほとんどを半眠っているという事実により、カフェインは私の主なエネルギー源です。したがって、あなたが正しく指摘するまで、私は私の偽物に気づきませんでした。
したがって、記録のために、私はあなたの2番目のアプローチを好む:SPを使用して現在のエラーを発生させ、次にパラメーターの検証にTRY/CATCHを使用する。
すべてのIF/BEGIN/ENDブロックの必要性が減少するため、行数が減少し、検証に焦点が戻ります。 SPのコードを読むとき、パラメーターに対して実行されているテストを確認できることが重要です。SQLパーサーを満たすためのすべての余分な構文のフラフが邪魔になります。意見。
通常、raiseerror()は回避し、エラーを示す値(負の数など)を返します。
if <errorcondition>
return -1
または、2つの出力パラメーターで結果を渡します。
create procedure dbo.TestProc
....
@result int output,
@errormessage varchar(256) output
as
set @result = -99
set @errormessage = null
....
if <errorcondition>
begin
set @result = -1
set @errormessage = 'Condition failed'
return @result
end
私は常に出力としてパラメーター@Is_Successビットを使用します。したがって、エラーが発生した場合は、@ Is_success = 0になります。親プロシージャが@ Is_Success = 0であることを確認すると、トランザクション(子トランザクションを含む)がロールバックされ、@ Error_Messageからクライアントにエラーメッセージが送信されます。
私はできるだけ早く帰宅することを好んでおり、手順の最後にすべてが同じ地点から帰ってくるのは意味がないと思います。数年前、私はこの習慣を身につけました。また、私は常に値を返します:
RETURN 10
アプリケーションは、正の数で致命的なエラーを表示し、負の値でユーザー警告メッセージを表示します。
エラーメッセージのテキストを含むOUTPUTパラメータを常に返します。
例:
IF ~error~
BEGIN
--if it is possible to be within a transaction, so any error logging is not ROLLBACK later
IF XACT_STATE()!=0
BEGIN
ROLLBACK
END
SET @OutputErrMsg='your message here!!'
INSERT INTO ErrorLog (....) VALUES (.... @OutputErrMsg)
RETURN 10
END