web-dev-qa-db-ja.com

特定の例外をキャッチする

C#を使用して特定の例外をキャッチするにはどうすればよいですか?
私のデータベースでは、いくつかの列に一意のインデックスがあります。
ユーザーが重複レコードを挿入すると、この例外がスローされました:

オブジェクト 'dbo .BillIdentity'と一意のインデックス 'IX _BillIdentity'に重複するキー行を挿入できません。ステートメントは終了されました。

この例外をどのようにキャッチできますか?
現在、私はこのコードを使用してチェックしています:

 catch (Exception ex) {
    if (ex.Message.Contains("Cannot insert duplicate key row in object 'dbo._BillIdentity' with unique index 'IX__BillIdentity")) {
        string ScriptKey = "$(function() {ShowMessage('Error');});";
        ScriptManager.RegisterStartupScript(Page, GetType(), "script", ScriptKey, true);
    }
}

臭いコードだと思います。
もっと良い方法はありますか?

17
Shahin

スローされる例外のtypeは表示されていませんが、その特定の例外タイプをキャッチできます。例えば:

catch (DuplicateKeyException e) {
    ...
}

このエラーjustに特定の例外タイプがない可能性がありますが、SqlExceptionのようなかなり一般的なものをキャッチする必要がある場合は、クラス自体の詳細については。たとえば、SqlExceptionにはErrorsプロパティがあり、データベース側の各(場合によっては複数の)エラーに関する詳細情報を確認できます。各 SqlError には、エラーのタイプを示す Number プロパティがあります。どうしても必要な場合はいつでもメッセージにフォールバックできますが、文化によってメッセージが変わる可能性などに注意する必要があります。

例外を実際に処理していない場合は、おそらくそれを再スローする必要があることに注意してください。

catch (SqlException e) {
    if (CheckWeCanHandle(e)) {
        // Mess with the ScriptManager or whatever
    } else {
        throw;
    }
}
17
Jon Skeet

この場合にのみSqlExceptionを処理します。

[編集]

MS SQLサーバーで重複キーの例外を確認するには:

try
{
    // try to insert
}
catch (SqlException exception)
{
    if (exception.Number == 2601) // Cannot insert duplicate key row in object error
    {
        // handle duplicate key error
        return;                  
    }
    else
        throw; // throw exception if this exception is unexpected
}

編集:2601はどこから来たのですか?

select *
from sys.messages
where text like 'Cannot insert duplicate key%'

戻り値:

message_id  language_id severity is_event_logged text
----------- ----------- -------- --------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2601        1033        14       0               Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'. The duplicate key value is %ls.

exception.Numberを使用し、sys.messagesビューを参照すると、特定のMSSQL例外を処理できます。

30
Alex Aza

私は誰かがこのルートをたどったプロジェクトを拾いました:

Catch ex As SqlException
    Select Case ex.Number
            Case 2601
                ...

次の点に注意してください(SQL Serverのsys.messagesから)。

2601-一意のインデックス '%。* ls'を持つオブジェクト '%。* ls'に重複するキー行を挿入できません。

しかし、これはどうですか..?

2627-%ls制約 '%。* ls'への違反。オブジェクト '%。* ls'に重複するキーを挿入できません。 "

私はちょうどこの問題を正確に追跡するのに少し時間を費やしました。

また、DBプロバイダーを変更するとどうなりますか?おそらく2601は絶対に普遍的ではありません...これは悪臭を放ちます、IMO。そして、プレゼンテーション層でこれを扱っているのであれば、もっと大きな質問があると思います。

この must が選択のメカニズムである場合は、それをDALの奥深くに埋め、カスタム例外を浸透させます。そうすることで、データストア(または理想的にはこのメカニズム)への変更の影響範囲がはるかに限定され、プレゼンテーション層で問題なくケースを一貫して処理できます。

私は現在、開いている接続でIDに対して軽量のSELECTを実行し、例外を完全に回避することに傾倒しています。

3
Tom Tom

フィルタの作業コードは、主キー違反の例外を複製するだけです

using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;

try {
    abc...
} catch (DbUpdateException ex) {
    if (ex.InnerException.InnerException is SqlException sqlEx && sqlEx.Number == 2601) {
        return ex.ToString();
    } else {
        throw;
    }
}

詳細に注意してください:-ex.InnerException.InnerExceptionではないex.InnerException

0
Tauqeer

文書化されているように ここ 、例外フィルターを使用できます。例:

try
{ /* your code here */ }
catch (SqlException sqlex) when (sqlex.Number == 2627)
{ /* handle the exception */ }
0
Will Menton

初心者のSqlExceptionしかキャッチできませんでした

catch (SqlException ex) {
    if (ex.Message.Contains("Cannot insert duplicate key row in object 'dbo._BillIdentity' with unique index 'IX__BillIdentity")) {
        string ScriptKey = "$(function() {ShowMessage('Error');});";
        ScriptManager.RegisterStartupScript(Page, GetType(), "script", ScriptKey, true);
    }
}
0
Mr47