Подтвердить что ты не робот

Entity Framework: как правильно обрабатывать исключения, возникающие из-за ограничений SQL

Я использую 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 (сломанная абстракция)

Знаете ли вы лучшее решение для этого? Спасибо за все отзывы..

Примечание: Я не хочу кодировать ограничения вручную на уровне приложения, я хочу иметь их в БД.

4b9b3361

Ответ 1

Вы должны уловить номер ошибки SQL (который SqlException.Number)

В этом случае это 2627, который был неизменным для SQL Server.

Если вы хотите абстракцию, у вас всегда будет какая-то зависимость от механизма базы данных, потому что каждый из них будет генерировать разные номера исключений и сообщения.

Ответ 2

Один из способов - проверить свойство Свойство Ошибок внутреннего исключения SqlException. Класс SqlError имеет Свойство Number, которое идентифицирует точную ошибку. См. Таблицу master.dbo.sysmessages для списка всех кодов ошибок.

Конечно, это все еще связывает вас с Sql Server. Я не знаю, как отвлечь это, кроме того, что вы катите свой "анализатор исключений EF".

Ответ 3

Этот сценарий не должен происходить, поскольку ключ никогда не должен назначаться явно при использовании EF; что позволяет контексту назначать соответствующий. Если это проблема с concurrency, вы должны сделать обновление в области транзакции.

Затем, если у вас есть UpdateException, вы можете повторить обновление снова. Вы можете безопасно сделать это в области транзакций и только заполнить область, когда обновление будет полным. В этом случае вероятность обновления, следующего в следующий раз, больше, чем первая.