捕获特定异常

时间:2011-05-25 06:31:15

标签: c# exception-handling refactoring

如何使用c#捕获特定异常?
在我的数据库中,某些列上有唯一索引 当用户插入重复记录时,抛出此异常:

  

无法插入重复的键行   对象'dbo。 BillIdentity'具有独特性   index'IX _BillIdentity'。该   声明已被终止。

如何捕获此异常?
目前我正在检查使用此代码:

 catch (Exception ex) {
    if (ex.Message.Contains("Cannot insert duplicate key row in object 'dbo._BillIdentity' with unique index 'IX__BillIdentity")) {
        string ScriptKey = "$(function() {ShowMessage('Error');});";
        ScriptManager.RegisterStartupScript(Page, GetType(), "script", ScriptKey, true);
    }
}

我认为它的难闻的气味代码 还有更好的办法吗?

6 个答案:

答案 0 :(得分:28)

仅在这种情况下处理SqlException

<强> [编辑]

检查MS SQL服务器中的重复键异常:

try
{
    // try to insert
}
catch (SqlException exception)
{
    if (exception.Number == 2601) // Cannot insert duplicate key row in object error
    {
        // handle duplicate key error
        return;                  
    }
    else
        throw; // throw exception if this exception is unexpected
}

编辑: 2601来自哪里?

select *
from sys.messages
where text like 'Cannot insert duplicate key%'

返回:

message_id  language_id severity is_event_logged text
----------- ----------- -------- --------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2601        1033        14       0               Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'. The duplicate key value is %ls.

使用exception.Number并引用sys.messages视图,您可以处理任何特定的MS SQL异常。

答案 1 :(得分:12)

您没有显示抛出的异常的类型,但您可以捕获该特定异常类型。例如:

catch (DuplicateKeyException e) {
    ...
}

只有这个错误可能没有特定的异常类型 - 但是如果你必须抓住像SqlException那样相当普遍的东西,你可以在其中查找更多细节班级本身。例如,在SqlException中有一个Errors属性,您可以在其中查看有关数据库端每个(可能是多个)错误的更多详细信息。然后每个SqlError都有一个Number属性,它将给出错误类型。如果你绝对必须,你总是可以回到这个消息,但是你需要知道消息在不同文化等方面的变化。

请注意,如果你真的没有处理异常,你应该重新抛出它:

catch (SqlException e) {
    if (CheckWeCanHandle(e)) {
        // Mess with the ScriptManager or whatever
    } else {
        throw;
    }
}

答案 2 :(得分:1)

我刚刚选择了一个有人走这条路的项目:

Catch ex As SqlException
    Select Case ex.Number
            Case 2601
                ...

请注意以下内容(来自SQL Server中的sys.messages):

2601 - 无法在对象'%。* ls'中插入具有唯一索引'%。* ls'的重复键行。

但是这个怎么样??

2627 - 违反%ls约束'%。* ls'。无法在对象'%。* ls'中插入重复键。“

我只花了一些时间来追踪这个问题。

如果我们更改数据库提供商怎么办?据推测2601并不是绝对普遍......这很臭,IMO。如果您在演示层中处理此问题,我认为还有更大的问题要问。

如果必须选择的机制,请将其深入,深入DAL并让自定义异常渗透。这样,对数据存储(或理想情况下,这种机制)的更改具有更有限的效果区域,您可以在表示层中始终如一地处理案例。

我目前倾向于在开放式连接上为ID做一个轻量级的SELECT并完全避免异常。

答案 3 :(得分:0)

你只能抓住初学者的SqlException

catch (SqlException ex) {
    if (ex.Message.Contains("Cannot insert duplicate key row in object 'dbo._BillIdentity' with unique index 'IX__BillIdentity")) {
        string ScriptKey = "$(function() {ShowMessage('Error');});";
        ScriptManager.RegisterStartupScript(Page, GetType(), "script", ScriptKey, true);
    }
}

答案 4 :(得分:0)

here所述,您可以使用异常过滤器。示例:

try
{ /* your code here */ }
catch (SqlException sqlex) when (sqlex.Number == 2627)
{ /* handle the exception */ }

答案 5 :(得分:0)

仅用于过滤器的工作代码重复的主键冲突异常

using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;

try {
    abc...
} catch (DbUpdateException ex) {
    if (ex.InnerException.InnerException is SqlException sqlEx && sqlEx.Number == 2601) {
        return ex.ToString();
    } else {
        throw;
    }
}

请注意细节:-ex.InnerException.InnerException而非ex.InnerException