プログラム実行フロー制御が期待どおりに例外をキャッチしますか?
-
02-07-2019 - |
質問
私は、例外が定期的にスローされることを期待し、それをフロー ロジックとして使用するのは悪いことだと常々感じていました。例外は、そうあるべきだと感じます。」例外」。例外を予期し、それを計画している場合、少なくとも .NET ではコードをリファクタリングする必要があることを示しているようです...
しかし。最近のシナリオを見て立ち止まりました。しばらく前にこれを msdn に投稿しましたが、これについてさらに議論を深めたいと考えており、ここは最適な場所です。
したがって、他のいくつかのテーブルに対する外部キーを持つデータベース テーブルがあるとします (最初に議論を引き起こしたケースでは、それを指す 4 つの外部キーがありました)。外部キー参照がない場合に限り、ユーザーに削除を許可したいとします。カスケード削除は望ましくありません。
通常、参照があるかどうかを確認するだけで、参照がある場合は、削除する代わりにユーザーに通知します。関連テーブルがオブジェクトのメンバーであるため、LINQ でこれを記述するのは非常に簡単でリラックスできるため、Section.Projects や Section.Categories などはインテリセンスなどを使用して入力するのが便利です。
しかし実際には、LINQ は、そのレコードを指す結果行があるかどうかを確認するために 4 つのテーブルすべてにアクセスする必要がある可能性があり、データベースにアクセスすることは明らかに常に比較的負荷の高い操作です。
このプロジェクトのリーダーは、コード 547 (外部キー制約) の SqlException をキャッチし、そのように処理するように変更するように私に依頼しました。
私は...
耐性のある.
しかし、この場合、おそらく 4 つのテーブル ヒットを飲み込むよりも、例外関連のオーバーヘッドを飲み込む方がはるかに効率的です。特に、すべてのケースでチェックを行う必要がありますが、子供がいない場合は例外を免れることができるためです...
さらに、実際にはデータベースが参照整合性の処理を担当する必要があります。それがデータベースの仕事であり、それがうまく機能します...
それで彼らが勝ったので、私はそれを変えました。
あるレベルではまだそう感じている 間違っている 私にとってはだけど。
例外を予期して意図的に処理することについてどう思いますか?事前に確認するより効率が良さそうな場合は大丈夫でしょうか?あなたのコードを見る次の開発者にとって、それはより混乱を招くのでしょうか、それともそれほど混乱を招くのでしょうか?開発者がチェックを追加しようとは考えていない新しい外部キー制約についてデータベースが認識している可能性があるため、そのほうが安全なのでしょうか?それとも、ベストプラクティスとは正確に何だと思うかという観点の問題ですか?
解決
おお、
まず最初に、質問を少し整理していただけますか。よく考えられ、説明された質問を読むのはうれしかったのですが、理解するにはかなりの量でした。
簡単に言うと「はい」ですが、状況によって異なります。
- SQL クエリに多くのビジネス ロジックが関連付けられているアプリケーションがいくつかあります (政府が設計したものではありません!)。このような構造になっている場合、それが「すでに機能している」ため、経営陣が他の方法でそれを説得するのは困難になる可能性があります。
- この状況で、それは本当に大きな問題になるでしょうか?まだ電線を渡って戻ってくるのが1回なので。サーバーは、続行できないことに気づく前に多くのことを行いますか (つまり、アクションに対して一連のトランザクションが発生した場合、途中で落ちて時間を無駄にしますか?)。
- 最初に UI でチェックを行うことに意味はありますか?それはあなたのアプリケーションに役立ちますか?より優れたユーザーエクスペリエンスを提供できるとしたら?(すなわち、ウィザードでいくつかのステップを実行すると、ウィザードが開始され、ステップ 1) の後にフォールオーバーするために必要な情報がすべて揃っているにもかかわらず、フォールオーバーするケースを見たことがあります。
- 同時実行性が問題ですか?(古典的な場合のように) コミットが行われる前にレコードが削除/編集される可能性はありますか?
File.Exists
ブーブー)。
私の意見では:
私ならそうします 両方. 。早く失敗して、より良いユーザー エクスペリエンスを提供できれば、それは素晴らしいことです。予期される SQL (またはその他の) 例外はいずれにしてもキャッチされ、適切にフィードバックされる必要があります。
例外を目的以外に使用すべきではないというコンセンサスがあることは知っています。 特別な事情, ただし、ここではアプリケーションの境界を越えていることを忘れないでください。 何も期待しない. 。先ほども言いましたが、これは File.Exists
, 、意味はありません、とにかくアクセスする前に削除できます。
他のヒント
あなたのリードは完全に正しいです。例外は、突然の状況だけではなく、特に予想外の結果を報告する場合に当てはまります。
この場合でも外部キーのチェックは行われ、例外が通知されるメカニズムとなります。
絶対にやってはいけないのは、包括的な catchall ステートメントを使用して例外をキャッチして抑制することです。きめ細かい例外処理を行うことが、そもそも例外が設計された理由です。
あなたが正しいと思います、例外は処理するためにのみ使用されるべきです 予想外の ここでは、予想される結果を処理するために例外を使用しています。この場合は明示的に処理する必要がありますが、それでも例外をキャッチして、エラーの可能性を示します。
このケースがコード全体でこのように処理されるのでなければ、私はあなたの側に立つつもりです。パフォーマンスの問題は、それが実際に問題である場合にのみ提起されるべきです。それは、それらのテーブルのサイズと、この関数が使用される回数によって異なります。
いい質問ですね。しかし、私は答えを見つけます...怖い!
例外は GOTO の一種です。
私はこのように例外を使用するのは好きではありません。スパゲッティ コードにつながるからです。
そのような単純な。
あなたがやっていることは何も間違っていません。例外は必ずしも「例外的」ではありません。これらは、呼び出し側オブジェクトがニーズに応じてきめ細かいエラー処理を行えるようにするために存在します。
特定の SqlException をキャッチするのは正しいことです。これは、SQL Server が外部キー条件を伝達するメカニズムです。例外メカニズムの別の使用法を好む場合でも、これが SQL Server の方法です。
また、4 つのテーブルのチェック中に、チェックが完了する前、そのテーブルを読み取った後に、他のユーザーが関連レコードを追加する可能性があります。
依存関係があるかどうかを確認し、依存関係がない場合は削除するストアド プロシージャを呼び出すことをお勧めします。このようにして、整合性のチェックが行われます。
もちろん、シングルトン削除とシングルトン削除には別のストアド プロシージャが必要になるでしょう。一括削除中...バッチ削除では、子行を検索し、一括削除の対象ではない (子行を持つ) レコードのセットを返す可能性があります。
プログラム内のあらゆる場所で例外が発生するのは好きではありませんが、この場合は例外メカニズムを使用します。
LINQ でテストする場合でも、LINQ での整合性のテスト中に誰かが子レコードを挿入した場合に備えて、例外をキャッチする必要があります。とにかく例外をチェックする必要があるのに、なぜコードを複製するのでしょうか?
もう 1 つのポイントは、この種の「短距離」例外がメンテナンス上の問題を引き起こしたり、プログラムを読みにくくしたりすることはないということです。try、削除のための SQL 呼び出し、catch のすべてが 10 行のコード内にまとめられています。意図は明白です。
スタック内で上位の 5 つのプロシージャ呼び出しをキャッチする必要がある例外をスローするのとは異なります。その間にあるすべてのオブジェクトが正しく処理 (解放) されたことを確認するという問題があります。
例外は常に魔法の答えであるとは限りませんが、この状況で例外を使用するのは間違いではないと思います。
私の2セント、
イブ