#c# #entity-framework-4 #domain-driven-design #ddd-repositories
#c# #entity-framework-4 #дизайн, управляемый доменом #ddd-репозитории
Вопрос:
Ни один из примеров, которые я рассмотрел для шаблонов репозитория, не включает в себя какую-либо обработку ошибок. Почему это? Скажем, например, у меня есть это:
public virtual TItem Insert<TItem>(TItem item) where TItem:class,new()
{
dbContext.Set<TItem>().Add(item);
try
{
dbContext.SaveChanges();
}
catch (DbUpdateException)
{
return null;
}
return item;
}
Случай, когда мы нарушаем ограничение. Я перехватываю исключение DbUpdateException… Где будет находиться эта обработка ошибок, если не в самом репозитории?
Ответ №1:
В правильно спроектированной системе ограничения никогда не должны быть нарушены. Сделайте ваши объекты умнее: например, не используйте слепые автоматически реализуемые установщики.
Репозиторий — это не то место, где можно выполнять проверку данных. Подходящее место:
- Если вы проверяете просто «договорные» ограничения, например, «количество должно быть неотрицательным целым числом» или «не передавайте мне нулевого клиента», поместите логику в саму сущность (либо установщики, либо конструктор, либо изменяющие методы, в зависимости от обстоятельств).
- Если вы проверяете бизнес-логику, поместите ее в специализированные объекты (спецификации DDD, если хотите), которые абстрагируют эту логику.
Эти исключения должны возникать только тогда, когда вы запускаете свои модульные интеграционные тесты и получаете сбой, который покажет, что либо ограничения вашей базы данных не соответствуют вашей сущности, либо ваша сущность реализована неправильно. Так что вам определенно не следует catch
использовать их.
Ответ №2:
По большей части репозиторию не нужно беспокоиться об обработке исключений. Классы, которые используют репозитории, должны справиться с этим. В вашем примере зачем возвращать null при возникновении ошибки вставки? Разве это не менее понятно, чем просто выдача исключения?
Например, допустим, мы хотим вставить запись через репозиторий, а затем распечатать новый идентификатор. Предположим, что вставка завершится неудачей по какой-либо причине.
var myNewItem = myRepository.Insert(myItem);
Console.WriteLine("MyItem added with ID: {0}", myNewItem.ID);
Следуя шаблону в вашем вопросе, вы получите NullReference
исключение во второй строке, если Insert
произойдет сбой. Это немного странно. Это более четко видно DbUpdateException
в первой строке. Также лучше иметь возможность рассчитывать на Insert
всегда либо возврат допустимого экземпляра, либо выдачу исключения.
Комментарии:
1. У меня нет проблем с тем, чтобы он вызывал исключение DbUpdate, это чище, чем NullRefrence, я согласен. В тот день, когда мы использовали процедуру sotred, мы бы использовали if not exists. Очевидно, у меня есть константы в datamodel. Итак, как сделать объект достаточно умным, чтобы проверять наличие записи перед выполнением вставки?
2. Одним из подходов было бы использовать какой-нибудь валидатор перед выполнением вставки для проверки на соответствие ограничениям, чтобы вы могли предоставлять понятные сообщения об ошибках. Или вы могли бы перехватывать исключения ограничений, создаваемые базой данных во всем, что использует репозиторий. В любом случае, я не думаю, что задача репозитория заключается в том, чтобы выяснить, можно ли вставить запись.
3. Я согласен, я перейду этот мост, когда закончу код репозитория и фактически подключу некоторый DI для потребителя.