ネタもと:中の技術日誌ブログ「もうちょっと具体的に」
ただ登録処理の伝票名称の重複は不可となっている場合にはどうしましょう。
この重複不可エラーはもちろん業務的なエラーですから、アプリケーションを落としてはいけません。
方法としては、例外、クラス化などがあるでしょう。
int 登録処理(int 得意先ID, string "伝票名称") {
try {
return (int)com.execute();
} catch (SQLException ex){
if ( ex.Number = 2726 ) {
throw new KeyDuplicationException();
} else {
throw ex;
}
}
}
int 登録伝票ID;
エラーコード _error;
bool 登録処理(int 得意先ID, string "伝票名称") {
try {
登録伝票ID = com.execute();
return true;
} catch (SQLException ex){
if ( ex.Number = 2726 ) {
this._error = エラーコード.KeyDuplicate;
return false;
} else {
throw ex;
}
}
}
コメントにしようかと思ったけど、トラックバックで。
やっぱり、上ですかね。
.NET Framework の推奨事項として、「例外は使わない方向で」というのがあります。中さんも、「業務エラー」という言葉を出していますが、「業務上、想定されるものなのか」ということを、まず考える必要があります。想定されるなら、戻り値として表現します。
ただし、私は、もう一歩、考えてみたいと思っています。
アプリケーションとしては「想定されている」けれど、メソッドとして「想定しなければならないのか」、ということ。
この場合、重複エラーは、メソッドとして想定しなくて良い、と考えます。UI や事前チェックで弾くべし。あるいは、どこで業務エラーに読み替えるべきか、と言いましょうか。
さて、呼び出し側を考えます。というか、元々「戻り値を捨ててはいけない」という話なので、呼び出し側を抜きにして考えてはいけないと思います。
int 伝票ID;
try {
伝票ID = 登録処理(100, "新発売のWindows Vistaについて");
DataRow dr = 取得処理(伝票id); // catch ブロックによっては try ブロックの外
} catch (KeyDuplicationException ex) {
// 重複登録のみ、何らかの処理が必要
必要な処理
} finally {
必要な処理
}
// 例外も発生するので、場合によっては try - finally で括る
if (登録処理(100, "新発売のWindows Vistaについて") == false) {
if (this._error == エラーコード.KeyDuplicate) {
重複処理で必要な処理
} else {
その他のエラーで必要な処理
}
return などの処理
}
DataRow dr = 取得処理(伝票id);
下のコードで、this._error の判定ブロックにおける else ブロックは必要でしょうか?登録処理メソッドの内容を知っていれば、不要です。知らなければ、必要です。つまり、下のコードでは、ライブラリ ユーザがライブラリの中身を知っている必要があります。私は、そのような作り方は、あまり良くないと考えます。これは、戻り値が「エラーコード」列挙体であれば、また別ですが。しかし、MFC(Win32API?)の ERROR_SUCCESS には違和感を感じるので、同じように「エラーコード.NoError」とかも、違和感があるけど。
また、元々、「戻り値を捨ててはいけない」という話です。ここを考えると、下の方は、このような書き方も出来ます。そしてこれは、戻り値を捨てていることになってしまいます。よって、元のお題を満足しません。
登録処理(100, "新発売のWindows Vistaについて")
if (this._error == エラーコード.KeyDuplicate) {
重複処理で必要な処理
} else if (this._error == ...) {
その他のエラーで必要な処理
} else {
// エラー無し
DataRow dr = 取得処理(登録伝票ID);
}
じゃぁ、上のコードはどうか。重複しているという例外が上がってきますが、それを処理する必要がなければ、キャッチしなければいい。もし、例外の種類が増えても、業務エラーへの読み替え処理が必要な例外だけキャッチします。また、このアプリケーション固有の例外を MyApplicationException クラスを作ってそこから派生させておけば、一括した処理も可能です。
最後に。微細なところに突っ込んでおきます。コメントなら書かないんだけどね。私のブログだもん(^-^;
int 登録処理(int 得意先ID, string "伝票名称") {
try {
return (int)com.execute();
} catch (SQLException ex){
if ( ex.Number = 2726 ) {
throw new KeyDuplicationException(
"伝票名にはユニーク インデックスが作成されています。", ex);
} else {
throw;
}
}
}
catch ブロックの中で throw ex と書くと、この例外を投げた場所が、この行になってしまいます。実際には、com.execute() メソッドの中のはずなのに。そういうわけで、throw とのみ、書きます。
例外を生成するときは、例外メッセージを書くことが推奨されています(どこに書いてあったかは、忘れた)。また、InnerException に、元々の例外を記録しておきましょう。なお、ここに書いた例外メッセージは、エンド ユーザに見せるためのものではありません。反対に、Exception.ErrorMessage を、エンド ユーザに見せるような作りは控えましょう。
追加:事前チェックをする場合
// 事前チェックを行う
エラーコード errorCode;
try {
データベースをロックする処理
if (Is登録可能(100, "新発売のWindows Vistaについて", out errorCode) == true) {
int 伝票ID;
伝票ID = 登録処理(100, "新発売のWindows Vistaについて");
DataRow dr = 取得処理(伝票id);
} else {
エラー処理(errorCode);
}
} finally {
ロックを解除する処理
}
投稿日時 : 2007年1月15日 22:01