Q: SqlExceptionsを処理するより良い方法はありますか?
以下の例は、メッセージ内のテキストの解釈に依存しています。
Eg1:テーブルが存在しない場合に処理する既存のtry catchがあります。
最初にテーブルが存在するかどうかを確認できるという事実を無視します。
try
{
//code
}
catch(SqlException sqlEx)
{
if (sqlEx.Message.StartsWith("Invalid object name"))
{
//code
}
else
throw;
}
Eg2:重複キー例外を示すtry catchなし
if (sqlEx.Message.StartsWith("Cannot insert duplicate key row in object"))
解決策:SqlExceptionHelperの開始
//-- to see list of error messages: select * from sys.messages where language_id = 1033 order by message_id
public static class SqlExceptionHelper
{
//-- rule: Add error messages in numeric order and prefix the number above the method
//-- 208: Invalid object name '%.*ls'.
public static bool IsInvalidObjectName(SqlException sex)
{ return (sex.Number == 208); }
//-- 2601: Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'. The duplicate key value is %ls.
public static bool IsDuplicateKey(SqlException sex)
{ return (sex.Number == 2601); }
}
SqlExceptionには、確認できる Numberプロパティ があります。重複エラーの場合、番号は2601です。
catch (SqlException e)
{
switch (e.Number)
{
case 2601:
// Do something.
break;
default:
throw;
}
}
サーバーからすべてのSQLエラーのリストを取得するには、これを試してください。
SELECT * FROM sysmessages
更新
これは、C#6.0で簡素化できるようになりました
catch (SqlException e) when (e.Number == 2601)
{
// Do something.
}
並べ替え、種類。 データベースエンジンエラーの原因と解決策 を参照してください
class SqllErrorNumbers
{
public const int BadObject = 208;
public const int DupKey = 2627;
}
try
{
...
}
catch(SqlException sex)
{
foreach(SqlErrorCode err in sex.Errors)
{
switch (err.Number)
{
case SqlErrorNumber.BadObject:...
case SqllErrorNumbers.DupKey: ...
}
}
}
問題は、良いDALレイヤーがTRY/CATCH
insideT-SQL(ストアドプロシージャ)を-のようなパターンで使用することです。 例外処理およびネストされたトランザクション 。残念ながら、T-SQL TRY/CATCH
ブロックは元のエラーコードを生成できません。50000を超えるコードでは、newエラーを生成する必要があります。クライアント側で問題を処理します。 SQL Serverの次のバージョンには、T-SQL catchブロックから元の例外を再発生させる新しい THROW コンストラクトがあります。
エラーコードを使用する方が適切です。解析する必要はありません。
try
{
}
catch (SqlException exception)
{
if (exception.Number == 208)
{
}
else
throw;
}
208を使用する必要があることを確認する方法:
select message_id
from sys.messages
where text like 'Invalid object name%'
SQLサーバーで満たされたエラーメッセージのリストが必要な場合は、次のように表示できます。
SELECT *
FROM master.dbo.sysmessages
SQLExceptionを処理するより良い方法を探している場合は、いくつかの方法があります。まず、Spring.NETはあなたが探しているものと似たようなことをします(私は思う)。ここに彼らがしていることへのリンクがあります:
http://springframework.net/docs/1.2.0/reference/html/dao.html
また、メッセージを確認する代わりに、エラーコード(sqlEx.Number
)を確認できます。これは、どのエラーが発生したかを識別するためのより良い方法のようです。唯一の問題は、返されるエラー番号がデータベースプロバイダーごとに異なる場合があることです。プロバイダーの切り替えを計画している場合は、プロバイダーをそのままの状態で処理するか、この情報を変換する抽象化レイヤーを作成することに戻ります。
エラーコードと設定ファイルを使用してユーザーフレンドリーなエラーメッセージを翻訳およびローカライズした男の例を次に示します。
MS SQL 2008では、サポートされているエラーメッセージをテーブルsys.messagesにリストできます。
SELECT * FROM sys.messages
別のマシンからDBに接続するときに(たとえば、フォームのロード時に)SQLエラーをスローする可能性のある新人は、C#で最初にSQLサーバーデータベースを指すデータテーブルをセットアップすると、次のような接続がセットアップされます。
this.Table_nameTableAdapter.Fill(this.DatabaseNameDataSet.Table_name);
この行を削除して、MSDNなどで言及されている従来の接続文字列のようなものに置き換える必要がある場合があります。
私は最初にコード、C#7およびエンティティフレームワーク6.0.0.0を使用しています。わたしにはできる
Add()
{
bool isDuplicate = false;
try
{
//add to database
}
catch (DbUpdateException ex)
{
if (dbUpdateException.InnerException != null)
{
var sqlException = dbUpdateException.InnerException.InnerException as SqlException;
if(sqlException == null)
isDuplicate = IsDuplicate(sqlException);
}
}
catch (SqlException ex)
{
isDuplicate = IsDuplicate(ex);
}
if(isDuplicate){
//handle here
}
}
bool IsDuplicate(SqlException sqlException)
{
switch (sqlException.Number)
{
case 2627:
return true;
default:
return false;
}
}
N.B: dbにアイテムを追加するためのクエリが別のプロジェクト(レイヤー)にあります
重大度タイプに基づいてbasedを評価できます。これを使用するには、OnInfoMessageにサブスクライブする必要があります。
conn.InfoMessage += OnInfoMessage;
conn.FireInfoMessageEventOnUserErrors = true;
次に、OnInfoMessageには次のものが含まれます。
foreach(SqlError err in e.Errors) {
//Informational Errors
if (Between(Convert.ToInt16(err.Class), 0, 10, true)) {
logger.Info(err.Message);
//Errors users can correct.
} else if (Between(Convert.ToInt16(err.Class), 11, 16, true)) {
logger.Error(err.Message);
//Errors SysAdmin can correct.
} else if (Between(Convert.ToInt16(err.Class), 17, 19, true)) {
logger.Error(err.Message);
//Fatal Errors 20+
} else {
logger.Fatal(err.Message);
}}
このようにして、エラー番号ではなく重大度を評価し、より効果的にすることができます。重大度 こちら の詳細を確認できます。
private static bool Between( int num, int lower, int upper, bool inclusive = false )
{
return inclusive
? lower <= num && num <= upper
: lower < num && num < upper;
}