3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援→開発戻り浦島太郎状態の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。

(.Net)SQL Server でバックアップ時(復元時)の進行状況を取得しプログレスバーに表示する(説明編)

Widowsアプリケーションから SQL Server のバックアップ、リストア時に進捗をパーセント表示する方法です。

参考にさせてもらったのはSQLServer2005のバックアップ中に進行状況を得るには です。

ここを見ると、BACKUP DATABASE クエリに WITH STATS を加えると OleDbConnection.InfoMessage で進捗率を取得できるということでした。

SqlConnection クラスにも InfoMessage イベントはあったので簡単に実装できるかと思いきやここからが苦戦しました。

まず、SqlConnection.InfoMessage イベントで WITH STATS で指定した間隔毎にメッセージは習得できるんですが、InfoMessage イベント発生のタイミングが問題でした。どうやら、SqlCommand.ExecuteNonQuery() でクエリを処理し終わった後に InfoMessage イベントが1回だけ走っている用なのです。

クエリ中にたまったメッセージを1回の InfoMessage イベントでコレクションで渡してる感じのようです。

で、これをリアルタイムに(クエリ実行しながら) InfoMessage イベントを起こせないものかと思って MSDN さまよっているとありました。

MSDN:接続イベント (ADO.NET)の「InfoMessages としてのエラー処理」項目で、SqlConnection の FireInfoMessageEventOnUserErrors プロパティを true に設定すると、InfoMessage イベントを発生できる あります。

MSDN:SqlConnection.FireInfoMessageEventOnUserErrors プロパティ のリファレンスを見てみると、「FireInfoMessageEventOnUserErrors を true に設定した場合、それまで例外として処理されていたエラーが InfoMessage イベントとして処理されるようになります。すべてのイベントは即座に発生し、イベント ハンドラによって処理されます。FireInfoMessageEventOnUserErrors を false に設定した場合、InfoMessage イベントはプロシージャの最後で処理されます。 」とありました。

ということで、SqlConnection.FireInfoMessageEventOnUserErrors プロパティを true に指定すると、リアルタイムに InfoMessage イベントが発生し、進捗状況を取得することができるようになりました。

うまくいったかのように思ったんですが、ここでさらに問題が。。

SqlConnection.FireInfoMessageEventOnUserErrors = true にしたことによって、本来クエリ中で発生してた例外がスローしなくなったっぽいのです。

本来 FireInfoMessageEventOnUserErrors プロパティを true にすると例外として処理されていたエラーが InfoMessage イベントとして処理され、例外を発生させなくするものなので、当然と言えば当然。。

しかし、クエリを Try Catch でくくっており例外処理ありきでコーディングしているため、何とかして、例外発生時に Catch で例外を捕捉したいものです。

いろいろ探しまたが、結局スマートな方法はなかったので、強引な方法で行きました。

InfoMessage イベント内でエラーの重大度レベルが一定以上(今回は11以上)なら、FireInfoMessageEventOnUserErrors を false にして ApplicationException を throw するようにしたのです。

あともうひとつスマートではないのは進捗率をプログレスバーに表示するための値ですが、InfoMessage イベントで取得する進行状況のメッセージは "○○ パーセント処理されました。" というものです。仕方なく "パーセント処理されました。" を削除して、int にキャストするようにしました。

とういことで説明が長くまりしたが、コードはこんな感じです。(復元用は省略。バックアップとSQLのクエリが違うだけなので。。)

プログレスバーは別のフォームに貼り付けており、マルチスレッドで値を更新しています。(いつもお世話になっている進行状況ダイアログを表示するを参考にしてます)

と思ってコードを貼り付けようとしたら、Exciteブログが文字数超過エラー。。

仕方なく2ページに分けました。

(.Net)SQL Server でバックアップ時(復元時)の進行状況を取得しプログレスバーに表示する(ソース編)でコードのっけてます。

追記:

SQL Server インストール時に、クライアント ツールをインストールするオプションを選択することで、SMO というSQL Server 管理オブジェクトから容易にバックアップやリストアその他の処理ができるようです。(SQL Server ManagementStudio は内部的に SMO を使ってるっぽいです。)

この記事で取り上げてる進捗率取得ももっと容易にできるようです。

ただ、クライアントツールが入ってないといけないのがちょっとネックですね。

SMO については MSDNマガジン:SQL Server 管理オブジェクトで紹介されてます。(進行状況のサンプルもあります。)