SQL Server の RAISERROR と ADO.NET で嵌る
こんにちは、naginoです。
今日は技術情報ではなく、単なる記録です。
後日関連情報をまとめて別記事に仕立て直すかもしれません。
●始まり
ADO.NET で SQL Server に複雑な更新処理を行っています。
処理結果に応じて分岐したいのですが、結果を SELECT で返すのは美しくないと思い、RAISERROR で返そうとしました。
結果は、起動させた Excel で新しいブックを作成し、そこに表示させます。
ただし、更新処理はループで繰り返し行い、また失敗しても重大なエラーではないため、エラーレベルは 1(警告) が妥当です。
なお、更新するかどうかの条件自体も複雑なため、一括更新ではなくあえてループで 1 件ずつ更新しています。
また、処理時間がそれぞれ長く、各更新処理は独立なため、カーソルは使いません。
作成しているプログラムは、別会社開発の既存システムに対するサポートツールで、サーバ側に変更を加えたくないため、ストアドプロシージャも使いません。
●RAISERROR を受け取る
プログラム側で RAISERROR を受け取るには SqlInfoMessageEventHandler が必要なため、実装します。
実装に当たっては MSDN のサンプルを参考にします。
http://msdn.microsoft.com/ja-jp/library/a0hee08w(VS.80).aspx
イベントハンドラの第 2 引数からエラーの内容を取得できるため、その内容を呼び出し元に返します。
●問題発生
・・・返し方が困りました。
イベントハンドラの 第 1 引数は SqlConnection クラスのため、実際に処理を実装している独自クラスの参照が得られず、インスタンス変数にたどり着けません。
サンプルでは static なメソッドですので、元のクラスに static な変数を用意してしまうのは手ですが、個々の更新処理は独立で並列実行が可能なため、将来のマルチスレッド化の可能性を考えると採用したくありません。
例外を throw するのは手ですが、独自クラスでの単なる try~catch では補足できませんでした。
これは内部的には別スレッドのせいかも知れないのですが、調べ切れていません。
(現在の目標は実装であって、仕組みの理解ではないため)
●妥協策
結局イベントハンドラを static ではなくして、インスタンス変数に放り込むことを検討しましたが、これは static なメソッドと変数のケースと変わらないので、結局 static で行くことにしました。
多くても 1000 回程度の処理のため、マルチスレッドにするほどではないかなという判断です。
●謎
ASP.NET では RAISERROR は使わず、おとなしく SELECT で結果を返したほうが賢いのでしょうかね。
SqlInfoMessageEventHandler 内でログファイルに書き出しまでするというのであれば問題なさそうなんですが、こういう画面表示として出力するケースは実装方法が分からないです。
何か良い解決方法、ありませんかね・・・?