69

问:有没有更好的方法来处理 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); }
}
4

9 回答 9

147

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.
}
于 2011-06-03T01:04:51.837 回答
20

有点,有点。请参阅数据库引擎错误的原因和解决方法

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(存储过程)中,具有像异常处理和嵌套事务这样的模式。唉,一个 T-SQLTRY/CATCH块不能引发原始错误代码,将不得不引发一个的错误,代码高于 50000。这使得客户端处理成为一个问题。在 SQL Server 的下一版本中,有一个新的THROW构造,它允许从 T-SQL 捕获块中重新引发原始异常。

于 2011-06-03T01:15:14.400 回答
9

最好使用错误代码,您不必解析。

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

    }
    else
        throw;
}

如何找出应该使用 208:

select message_id
from sys.messages
where text like 'Invalid object name%'
于 2011-06-03T01:03:51.423 回答
4

如果您想要在 Sql server 中遇到的错误消息列表,您可以查看

SELECT *
FROM master.dbo.sysmessages
于 2012-06-21T13:04:12.733 回答
2

您可以根据严重性类型进行评估。注意要使用它,您必须订阅 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;
}
于 2016-08-31T07:10:21.307 回答
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

于 2011-06-03T01:03:33.227 回答
1

使用 MS SQL 2008,我们可以在 sys.messages 表中列出支持的错误消息

SELECT * FROM sys.messages
于 2013-04-15T08:26:43.490 回答
1

我首先使用代码、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;
    }
}

注意:我对向数据库添加项目的查询在另一个项目(层)中

于 2017-12-11T07:15:11.100 回答
0

对于那些在从另一台机器连接到数据库时可能会抛出 SQL 错误的新手(例如,在表单加载时),你会发现当你第一次在 C# 中设置一个指向 SQL 服务器数据库的数据表时它将建立这样的连接:

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

您可能需要删除此行并将其替换为其他内容,例如 MSDN 中提到的传统连接字符串等。

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

于 2013-03-01T16:08:56.683 回答