[英]How to catch a specific SqlException error?
問:有沒有更好的方法來處理 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 層會在T-SQL(存儲過程)中使用TRY/CATCH
,使用類似異常處理和嵌套事務的模式。 唉,T-SQL TRY/CATCH
塊不能引發原始錯誤代碼,將不得不引發一個新錯誤,代碼高於 50000。這使得客戶端處理成為問題。 在 SQL 服務器的下一版本中,有一個新的THROW構造,允許從 T-SQL 捕獲塊重新引發原始異常。
最好使用錯誤代碼,您不必解析。
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
您可以根據嚴重性類型進行評估。 注意要使用它,您必須訂閱 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;
}
使用 MS SQL 2008,我們可以在 sys.messages 表中列出支持的錯誤消息
SELECT * FROM sys.messages
我首先使用代碼 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;
}
}
注意:我對向數據庫添加項目的查詢在另一個項目(層)中
如果您正在尋找一種更好的方法來處理 SQLException,您可以做幾件事。 首先,Spring.NET 做了一些類似於你正在尋找的東西(我認為)。 這是他們正在做的事情的鏈接:
http://springframework.net/docs/1.2.0/reference/html/dao.html
此外,您可以檢查錯誤代碼 ( sqlEx.Number
),而不是查看消息。 這似乎是識別發生哪個錯誤的更好方法。 唯一的問題是每個數據庫提供者返回的錯誤號可能不同。 如果您打算切換供應商,您將回到原來的方式來處理它,或者創建一個抽象層來為您翻譯這些信息。
這是一個使用錯誤代碼和配置文件來翻譯和本地化用戶友好錯誤消息的人的示例:
對於那些在從另一台機器連接到數據庫時可能會拋出 SQL 錯誤的新手(例如,在表單加載時),您會發現當您第一次在 C# 中設置一個指向 Z977852840A01740CBB0876 服務器數據庫的數據表時它將建立這樣的連接:
this.Table_nameTableAdapter.Fill(this.DatabaseNameDataSet.Table_name);
您可能需要刪除此行並將其替換為其他內容,例如 MSDN 中提到的傳統連接字符串等。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.