捕获特定异常

Sha*_*hin 16 c# refactoring exception-handling

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

无法在对象'dbo中插入重复的键行.BillIdentity'具有独特的指数'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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我觉得它的味道很难闻.
有没有更好的方法?

Ale*_*Aza 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
}
Run Code Online (Sandbox Code Playgroud)

编辑:2601来自哪里?

select *
from sys.messages
where text like 'Cannot insert duplicate key%'
Run Code Online (Sandbox Code Playgroud)

返回:

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.
Run Code Online (Sandbox Code Playgroud)

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


Jon*_*eet 17

您还没有显示的类型被抛出的异常的,但你可以捕捉特定的异常类型.例如:

catch (DuplicateKeyException e) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

这有可能是不会有特定的异常类型只是这个错误-但如果你必须抓住的东西相当普遍的喜欢SqlException,你可以再去找类本身内的更多细节.例如,SqlException在某个Errors属性中,您可以查看有关数据库端每个(可能是多个)错误的更详细信息.SqlError然后每个都有一个Number属性,它将给出错误类型.如果你绝对必须,你可以随时回到消息,但是你需要知道消息改变的可能性,以适应不同的文化等.

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

catch (SqlException e) {
    if (CheckWeCanHandle(e)) {
        // Mess with the ScriptManager or whatever
    } else {
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*Tom 6

我刚刚拿起一个项目,有人沿着这条路走下去:

Catch ex As SqlException
    Select Case ex.Number
            Case 2601
                ...
Run Code Online (Sandbox Code Playgroud)

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

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

但是这个..?

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

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

如果我们更改数据库提供程序会怎样?大概 2601 不是绝对通用的......这很臭,IMO。如果你(正在)在你的表示层处理这个问题,我认为还有更大的问题要问。

如果这必须是选择的机制,请将其深埋在 DAL 的深处,并让自定义异常渗透。这样,对数据存储(或理想情况下,此机制)的更改具有更有限的影响区域,您可以一致地处理案例,而不会在表示层中出现任何问题。

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