2011-06-03 256 views
50

问:有没有更好的方法来处理SqlExceptions?SqlException捕获和处理

以下示例依赖于解释消息中的文本。

Eg1:我有一个现有的try catch来处理,如果一个表不存在。
忽略我可以检查表格是否存在的事实。

try 
{ 
    //code 
} 
catch(SqlException sqlEx) 
{ 
     if (sqlEx.Message.StartsWith("Invalid object name")) 
     { 
      //code 
     } 
     else 
      throw; 
} 

为Eg2:没有尝试捕捉显示重复键异常

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); } 
} 
+5

为什么我突然看完这个激起了? – Adrian 2017-05-18 03:18:51

回答

105

SQLException中有Number property,你可以检查。重复错误的数量是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. 
} 
+1

你可以用语言进行过滤:select * from sysmessages where msglangid = 1033。这是英语 – 2016-06-25 04:50:11

+0

您好@Richard Schneider我知道这个答案已经过时,但我想知道是否有新的(更好的)解决方案也自动创建消息,因为我使用MVC,并且每个模型属性都有自己的“翻译”I会假设我可以用属性名称编写标准消息(因为我每次映射它们都完全相同),并获取重命名的属性名称以显示消息,如“已经有一个以[Value]为已知的记录为[FieldName ]在我们的系统中,请选择不同的方式“。 – 2016-10-24 16:03:31

+0

感谢您的C#6.0更新,非常有用 – 2017-01-14 01:47:22

1

如果你正在寻找一个更好的处理SQLException的方法,有几件事情你可以做。首先,Spring.NET与你正在寻找的东西类似(我认为)。这里是一个链接到他们在做什么:

http://springframework.net/docs/1.2.0/reference/html/dao.html

此外,而不是看消息,你可以检查错误代码(sqlEx.Number)。这似乎是确定发生错误的更好方法。唯一的问题是每个数据库提供者返回的错误号可能不同。如果您打算切换提供程序,您将回到按照自己的方式处理它,或者创建一个抽象层来为您转换此信息。

这里是谁使用的错误代码和配置文件翻译和本地化用户友好的错误消息的人的例子:

https://web.archive.org/web/20130731181042/http://weblogs.asp.net/guys/archive/2005/05/20/408142.aspx

+0

谢谢你的第二个链接 – 2011-06-03 01:15:53

+0

第二个链接中断 – sweetfa 2016-09-18 04:59:20

+0

使用archive.org链接来修复断开的链接。 – IAmTimCorey 2016-09-19 15:31:26

7

这是更好地使用错误代码,你不”不得不解析。

try 
{ 
} 
catch (SqlException exception) 
{ 
    if (exception.Number == 208) 
    { 

    } 
    else 
     throw; 
} 

如何找出208应使用:

select message_id 
from sys.messages 
where text like 'Invalid object name%' 
+0

感谢您的意见。我将创建一个SqlException帮助器。另外,非常感谢您将我指向错误的sql表。 select * from sys.messages where language_id = 1033 – 2011-06-03 01:14:36

+0

select * from master.dbo.sysmessages其中msglangid = 1033 或 SELECT * FROM sys.messages WHERE language_id = 1033 只能过滤英文消息。 此外,系统表中的message_id与SqlException.Number不是一对一映射。我已经在C#和SQL Server 2008 R2上验证了超时错误SqlException。数是-2,但系统表中没有这样的错误定义。 – zhaorufei 2013-04-24 03:35:25

20

排序,种类。见Cause and Resolution of Database Engine Errors

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的T-SQL(存储过程),与像Exception handling and nested transactions的模式。唉,一个T-SQL TRY/CATCH块无法提高原始错误代码,将不得不提高新的错误,代码高于50000.这使得客户端处理问题。在下一个版本的SQL Server中,有一个新的THROW构造,允许从T-SQL catch块重新引发原始异常。

+8

感谢您的建议和链接。顺便说一句:我喜欢捕捉性:)我将开始使用,而不是sqlEx的乐趣。让我想起旧的经典asp天'On Error Goto Hell' – 2011-06-03 01:18:30

+1

这听起来不太正确,错误在sex.Errors;) – divyanshm 2015-07-06 13:00:55

3

如果你想在SQL Server中遇到的错误消息列表,你可以用

SELECT * 
FROM master.dbo.sysmessages 
0

对于那些你新秀在那里的另一台机器连接到数据库时,谁可以抛出一个SQL错误(见例如,在形式负载),你会发现,当你第一次安装在C#中的数据表,它指向一个SQL Server数据库,它会设置这样的连接:

this.Table_nameTableAdapter.Fill(this.DatabaseNameDataSet.Table_name); 

您可能需要删除此行,将其替换为像传统连接字符串那样的其他东西在表中定义在MSDN等

http://www.connectionstrings.com/sql-server-2008

1

随着MS SQL 2008年,我们可以列出支持的错误信息sys.messages

SELECT * FROM sys.messages 
0

您可以严重性类型评估基于。 注意要使用这个,你必须订阅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); 
}} 

这样你就可以评估其严重性,而不是错误数量,更有效。您可以在严重性here中找到更多信息。

private static bool Between(int num, int lower, int upper, bool inclusive = false) 
{ 
    return inclusive 
     ? lower <= num && num <= upper 
     : lower < num && num < upper; 
} 
0

我正在使用代码第一,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是在另一个项目(层)

+0

我有问题找到包含DbUpdateException的名称空间。我正在使用实体框架5.0.0.0。但是当我尝试在DbUpdateException的catch语句中声明一个Exception类型时,它显示我缺少一个程序集或引用。当我在MSDN中查找该异常类型时,它说它是EntityFrameworkCore 2.0的一部分。 – user1161391 2018-02-02 19:37:11

+0

没关系。在System.Data.Entity.Infrastructure中找到它。但不应该读取代码if(sqlException!= null) isDuplicate = IsDuplicate(sqlException); – user1161391 2018-02-02 19:44:32

+0

@ user1161391我认为它执行第一个catch(DbUpdateException ex)。它同样在这里 – 2018-02-04 06:04:21