Entity Framework:如何正确处理由于SQL约束引起的异常

17

我使用Entity Framework访问我的SQL数据。我的数据库模式中有一些约束条件,我想知道如何处理由这些约束条件导致的异常。

例如,在两个用户尝试同时向数据库添加(几乎)相同的实体时,我会遇到以下异常:

System.Data.UpdateException
"An error occurred while updating the entries. See the InnerException for details."

(inner exception) System.Data.SqlClient.SqlException
"Violation of UNIQUE KEY constraint 'Unique_GiftId'. Cannot insert duplicate key in object 'dbo.Donations'.\r\nThe statement has been terminated."

我应该如何正确地捕获这个特定的异常?

不完美的解决方案:

    catch (UpdateException ex)
    {
        SqlException innerException = ex.InnerException as SqlException;
        if (innerException != null && innerException.Message.StartsWith("Violation of UNIQUE KEY constraint 'Unique_GiftId'"))
        {
            // handle exception here..
        }
        else
        {
            throw;
        }
    }

现在虽然这种方法可以工作,但它有一些缺点:

  • 没有类型安全性:代码依赖于包含唯一列名称的异常消息。
  • 依赖于SqlCLient类(破坏了抽象)

你知道更好的解决方案吗? 感谢所有的反馈..

注意:我不想在应用程序层手动编写约束条件,我希望将它们放在数据库中。

3个回答

17

你应该能够捕获SQL错误号码(它是SqlException.Number

在这种情况下,它是2627,对于SQL Server来说,这个错误号码一直没有变化。

如果你需要抽象化,那么你将始终依赖于数据库引擎,因为每个引擎都会抛出不同的异常号码和消息。


好的,但是即使我使用这个ID,我也必须解析异常信息以获取列名。 - driAn
@driAn:正确。SQL也没有本地机制来钻取约束或列,这意味着没有API或类似的东西可以读取它。 - gbn

2
一种方法是检查内部SqlException的 Errors属性。 SqlError类有一个 Number属性,用于标识确切的错误。请参阅master.dbo.sysmessages表以获取所有错误代码的列表。
当然,这仍然将您与Sql Server绑定在一起。除了自己编写“EF异常分析器”外,我不知道还有其他抽象化它的方法。

0

这种情况不应该发生,因为在使用EF时,关键字不应该被显式地分配,而是允许上下文分配一个适当的关键字。如果这是并发问题,则应在事务范围内进行更新。

然后,如果出现UpdateException,您可以再次重试更新。您可以在事务范围内安全地执行此操作,并且仅在更新成功时完成范围。在这种情况下,下一次更新成功的机会比第一次更大。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接