17

我使用实体框架来访问我的 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 类的依赖(抽象中断)

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

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

4

3 回答 3

17

您应该能够捕获 SQL 错误号(即SqlException.Number

在这种情况下,它是 2627,这对于 SQL Server 来说永远相同。

如果您想要抽象,那么您将始终对数据库引擎有一些依赖,因为每个引擎都会抛出不同的异常编号和消息。

于 2010-09-12T10:02:03.480 回答
2

一种方法是检查内部 SqlException 的Errors 属性。SqlError 类具有标识确切错误的Number 属性。有关所有错误代码的列表,请参阅 master.dbo.sysmessages 表。

当然,这仍然将您与 Sql Server 联系在一起。除了推出您自己的“EF 异常分析器”之外,我不知道有什么方法可以将其抽象出来。

于 2010-09-12T10:00:12.437 回答
0

这种情况不应发生,因为在使用 EF 时不应显式分配密钥;而是允许上下文分配适当的上下文。如果它是一个并发问题,那么您应该在事务范围内进行更新。

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

于 2012-05-10T19:26:13.570 回答