例外が定期的にスローされることを期待して、それらをフロー ロジックとして使用することは悪いことだと常に感じていました。例外は、まあ、「例外」であるべきだと感じます。例外を予期して計画している場合、少なくとも .NET ではコードをリファクタリングする必要があることを示しているように思われます...
ただし。最近のシナリオで私は一時停止しました。これは少し前に msdn に投稿しましたが、それについてもっと議論したいと思います。ここは完璧な場所です!
したがって、他のいくつかのテーブルの外部キーを持つデータベース テーブルがあるとします (最初に議論を引き起こしたケースでは、それを指す 4 つの外部キーがありました)。ユーザーが削除できるようにしたいが、外部キー参照がない場合に限る。カスケード削除したくありません。
私は通常、参照があるかどうかを確認するだけで、参照がある場合は、削除する代わりにユーザーに通知します。関連するテーブルはオブジェクトのメンバーであるため、LINQ でそれを書くのは非常に簡単でリラックスできます
。そのレコードを指す結果行があるかどうかを確認するために、4 つのテーブルすべてをヒットする可能性があります。データベースをヒットすることは、明らかに常に比較的高価な操作です。
このプロジェクトのリーダーは、コード 547 (外部キー制約) で SqlException をキャッチし、そのように処理するように変更するように私に依頼しました。
私は…
抵抗しました。
しかし、この場合、4 つのテーブル ヒットを飲み込むよりも、例外関連のオーバーヘッドを飲み込む方がおそらくはるかに効率的です。子供がいないとき...
さらに、データベースは参照整合性の処理を担当する必要があり、それがその仕事であり、うまく機能します...
だから彼らは勝ち、私はそれを変更しました。
あるレベルでは、それでも私には間違っていると感じています。
例外を期待して意図的に処理することについてどう思いますか? 事前に確認するより効率が良さそうな場合は大丈夫ですか?次の開発者があなたのコードを見て混乱することはありますか?それとも混乱が少ないでしょうか? データベースは、開発者がチェックを追加することを考えていない可能性のある新しい外部キー制約を認識している可能性があるため、より安全ですか? それとも、ベスト プラクティスとは正確には何だと考えているかという視点の問題ですか?
8 に答える
あなたのリードは絶対に正しいです。例外はブルームーンの状況で一度だけではなく、特に予想外の結果を報告するためのものです。
この場合、外部キーのチェックは引き続き行われ、例外は通知を受け取るメカニズムです。
すべきでないことは、ブランケット キャッチオール ステートメントで例外をキャッチして抑制することです。細粒度の例外処理を行うことが、そもそも例外が設計された理由です。
わお、
まず、質問を少し掘り下げてください。よく考えられて説明された質問を読むのは良かったのですが、それは消化するのにかなりの量でした。
簡単な答えは「はい」ですが、状況によって異なります。
- SQLクエリに多くのビジネスロジックが関連付けられているアプリケーションがいくつかあります(私の設計Govではありません!)。これが構造化されている場合、「すでに機能している」ため、管理者は他の方法で納得させるのが難しい場合があります。
- この状況で、それは本当に大したことになるのでしょうか?それはまだワイヤーを横切って戻って1回の旅行なので。サーバーは、続行できないことに気付く前に多くのことを実行しますか(つまり、アクションに対して一連のトランザクションが発生した場合、サーバーは途中で失敗し、時間を無駄にしますか?)。
- 最初にUIでチェックを行うのは理にかなっていますか?それはあなたのアプリケーションに役立ちますか?それがより良いユーザーエクスペリエンスを提供する場合は?(つまり、ウィザードでいくつかのステップを実行し、ステップ1の後にフォールオーバーするために必要なすべての情報が揃ったときに、ウィザードが開始してからフォールオーバーする場合があります)。
- 並行性は問題ですか?コミットが行われる前に、レコードが削除/編集されたり、何かが行われたりする可能性はありますか(従来
File.Exists
のブーブーのように)。
私の意見では:
私は両方をします。私が早く失敗し、より良いユーザーエクスペリエンスを提供できれば、素晴らしいです。予想されるSQL(またはその他の)例外は、とにかくキャッチして適切にフィードバックする必要があります。
例外は例外的な状況以外には使用すべきではないというコンセンサスがあることは知っていますが、ここではアプリケーションの境界を越えていることを忘れないでください。何も期待していません。私が言ったように、これはのようなものFile.Exists
です、意味がありません、とにかくそれにアクセスする前にそれを削除することができます。
いい質問です。しかし、私は答えを見つけます...怖い!
例外は一種のGOTOです。
スパゲッティコードにつながるため、このように例外を使用するのは好きではありません。
そのような単純な。
私はあなたが正しいと思います、例外は予期しない結果を処理するためにのみ使用されるべきです、ここではおそらく予想される結果を処理するために例外を使用しています、あなたはこのケースを明示的に処理する必要がありますが、それでも可能性のあるエラーを示すために例外をキャッチします。
これがコード全体でこのケースが処理される方法でない限り、私はあなたの側にいます。パフォーマンスの問題は、それが実際に問題である場合にのみ発生する必要があります。つまり、これらのテーブルのサイズとこの関数が使用される回数によって異なります。
あなたがしていることに何も問題はありません。例外は必ずしも「例外的」ではありません。これらは、呼び出し元のオブジェクトが必要に応じてきめ細かいエラー処理を行えるようにするために存在します。
特定のSqlExceptionをキャッチすることは正しいことです。これは、SQLServerが外部キー条件を伝達するメカニズムです。例外メカニズムの別の使用法を好む場合でも、これがSQLServerの方法です。
また、4つのテーブルのチェック中に、他のユーザーがチェックが完了する前に、そのテーブルを読んだ後に関連レコードを追加する場合があります。
依存関係があるかどうかを確認し、存在しない場合は削除するストアド プロシージャを呼び出すことをお勧めします。このようにして、整合性のチェックが行われます。
もちろん、シングルトン削除とバッチ削除には別のストアド プロシージャが必要になるでしょう... バッチ削除では、子行を探して、一括削除に適していない (子行があった) レコードのセットを返すことができます。 .
プログラムのいたるところに例外が見られるのは好きではありませんが、この場合は例外メカニズムを使用します。
LINQ でテストする場合でも、LINQ で整合性をテストしているときに誰かが子レコードを挿入した場合に備えて、例外をキャッチする必要があります。とにかく例外をチェックする必要があるので、なぜコードを複製するのですか?
もう 1 つのポイントは、この種の「短い範囲」の例外はメンテナンスの問題を引き起こさず、プログラムを読みにくくすることもありません。try、delete の SQL 呼び出し、および catch をすべて 10 行のコードでまとめます。その意図は明らかです。
キャッチされる例外をスローするのとは異なり、スタックの上部にある 5 つのプロシージャ コールが呼び出され、間にあるすべてのオブジェクトが正しく処理 (解放) されていることを確認するという問題があります。
例外は常に魔法の答えとは限りませんが、この状況で例外を使用しても問題はないと思います。
私の2セント、
イヴ