如何捕获特定的 SqlException 错误?

发布于 2024-11-13 22:43:24 字数 1211 浏览 3 评论 0 原文

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

Q: Is there a better way to handle SqlExceptions?

The below examples rely on interpreting the text in the message.

Eg1: I have an existing try catch to handle if a table does not exist.
Ignore the fact that I could check if the table exists in the first place.

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

Eg2: without the try catch showing duplicate key exception

if (sqlEx.Message.StartsWith("Cannot insert duplicate key row in object"))

Solution: The start of my 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); }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

明媚如初 2024-11-20 22:43:24

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.
}

The SqlException has a Number property that you can check. For duplicate error the number is 2601.

catch (SqlException e)
{
   switch (e.Number)
   {
      case 2601:
         // Do something.
         break;
      default:
         throw;
   }
 }

To get a list of all SQL errors from you server, try this:

 SELECT * FROM sysmessages

Update

This can now be simplified in C# 6.0

catch (SqlException e) when (e.Number == 2601)
{
   // Do something.
}
拔了角的鹿 2024-11-20 22:43:24

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

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 Server 的下一个版本中,有一个新的 THROW 构造允许从 T-SQL catch 块重新引发原始异常。

Sort of, kind of. See 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: ...
      }
   }
}

The problem though is that a good DAL layer would us TRY/CATCH inside the T-SQL (stored procedures), with a pattern like Exception handling and nested transactions. Alas a T-SQL TRY/CATCH block cannot raise the original error code, will have to raise a new error, with code above 50000. This makes client side handling a problem. In the next version of SQL Server there is a new THROW construct that allow to re-raise the original exception from T-SQL catch blocks.

苏别ゝ 2024-11-20 22:43:24

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

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

    }
    else
        throw;
}

如何找出应该使用208:

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

It is better to use error codes, you don't have to parse.

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

    }
    else
        throw;
}

How to find out that 208 should be used:

select message_id
from sys.messages
where text like 'Invalid object name%'
溺孤伤于心 2024-11-20 22:43:24

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

SELECT *
FROM master.dbo.sysmessages

If you want list of error messages met in Sql server, you can see with

SELECT *
FROM master.dbo.sysmessages
伴我老 2024-11-20 22:43:24

您可以基于严重性类型进行评估。
请注意,要使用此功能,您必须订阅 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;
}

You can evaluate based on severity type.
Note to use this you must be subscribed to OnInfoMessage

conn.InfoMessage += OnInfoMessage;
conn.FireInfoMessageEventOnUserErrors = true;

Then your OnInfoMessage would contain:

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

This way you can evaluate on severity rather than on error number and be more effective. You can find more information on severity here.

private static bool Between( int num, int lower, int upper, bool inclusive = false )
{
    return inclusive
        ? lower <= num && num <= upper
        : lower < num && num < upper;
}
望笑 2024-11-20 22:43:24

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

SELECT * FROM sys.messages

With MS SQL 2008, we can list supported error messages in the table sys.messages

SELECT * FROM sys.messages
百思不得你姐 2024-11-20 22:43:24

如果您正在寻找更好的方法来处理 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

If you are looking for a better way to handle SQLException, there are a couple things you could do. First, Spring.NET does something similar to what you are looking for (I think). Here is a link to what they are doing:

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

Also, instead of looking at the message, you could check the error code (sqlEx.Number). That would seem to be a better way of identifying which error occurred. The only problem is that the error number returned might be different for each database provider. If you plan to switch providers, you will be back to handling it the way you are or creating an abstraction layer that translates this information for you.

Here is an example of a guy who used the error code and a config file to translate and localize user-friendly error messages:

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

大姐,你呐 2024-11-20 22:43:24

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

注意:我将项目添加到数据库的查询位于另一个项目(层)中

I am working with code first, C# 7 and entity framework 6.0.0.0. it works for me

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: my query for add item to db is in another project(layer)

旧话新听 2024-11-20 22:43:24

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

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

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

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

For those of you rookies out there who may throw a SQL error when connecting to the DB from another machine(For example, at form load), you will find that when you first setup a datatable in C# which points to a SQL server database that it will setup a connection like this:

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

You may need to remove this line and replace it with something else like a traditional connection string as mentioned on MSDN, etc.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文