Как мне справиться с параллелизмом в отношении ссылок между агрегатными корнями? - PullRequest
0 голосов
/ 03 октября 2018

У меня есть Aggregate Root (Slave), который ссылается на другое AG (Master), то есть у меня есть ограничение внешнего ключа в БД.

Очень маловероятно, но все же возможно, что ссылка Master можно удалить прямо перед вставкой ссылки Slave.Это возможно, чтобы избежать использования repeatable read или serializable уровней изоляции транзакций, но это отрицательно влияет на производительность.

Я предпочитаю оптимистическую проверку параллелизма в этом случае: попытаться и может произойти сбой.Тем не менее, трудно отследить возвращение DbUpdateEception к семантике проблемы.

Другими словами, наличие текстового сообщения не очень удобно для понимания, КОТОРАЯ ссылка на самом деле не удалась:

Произошла ошибка при обновлении записей.Подробности см. Во внутреннем исключении.

Внутреннее исключение SqlException - «Оператор INSERT конфликтовал с ограничением FOREIGN KEY« FK_Slaves_Masters_MasterId ». Конфликт произошел в базе данных« EFExperiment », таблице« dbo.Masters », столбце« Id »'. Оператор был прерван. "

Я отсканировал SqlEception, и похоже, что ни индексное имя, ни таблица с именами столбцов, присутствующими там отдельно, только сообщение.Тем не менее было бы очень хорошо интерпретировать эту ошибку как «ReferencedEntityNotFoundException», содержащее имя и тип объекта.Это позволяет показать дружественное сообщение пользователю, объясняющее, что произошло:

Мастер (id = 123) больше не существует.Назначьте Раба другому.

Какой здесь лучший подход?Можно ли сделать сервер SQL более многословным и возвращать имена таблиц и столбцов, или мне нужно разобрать сообщение?Существует ли какая-либо библиотека расширений EF для этой цели?

PS Существует также возможность вообще удалить ограничение FK и разрешить существование висящих подчиненных устройств, показывающих их пользователю как имеющее недопустимое состояние.Но это определенно излишество.

1 Ответ

0 голосов
/ 03 октября 2018

Такой библиотеки нет, но для продолжения может быть достаточно ошибки с номером 547, возникающей в этом месте кода.

Кроме того, вы можете искать конкретное имя FK в сообщении.Извлечение имен объектов из сообщения об ошибке должно быть надежным, поскольку они являются частью вашего исходного кода и не зависят от языка.

например:

catch (SqlException ex)
{
    foreach (SqlError e in ex.Errors)
    {
        if (e.Number == 547 && e.Message.Contains("FK_Slaves_Masters_MasterId") )
        {
            throw new ReferencedEntityNotFoundException("Master", "Slave", slave.MasterId);
        }
    }

    throw;    
}
...