DDD: ссылка на сущность внутри совокупного корня по его идентичности
Я застрял в поиске правильного способа ссылаться на сущности, расположенные внутри совокупного корня, когда мы получаем только их идентификаторы из параметров URL. Я задал предыдущий вопрос, который был сосредоточен на объектах-значениях, поэтому я начинаю с другого примера.
Допустим, мы хотим изменить OrderLine
внутри Order
:
- Пользователь переходит на страницу, где он может видеть сводку заказа вместе со всеми его строками заказа.
- Пользователь нажимает кнопку редактирования рядом со строкой заказа.
- Он направляется к
edit-order-line?orderId=x&orderLineId=y
Теперь, если мне нужно обновить количество в Order Line, я могу сделать:
Order order = orderRepository.find(orderId);
order.updateQuantity(orderLineId, 2);
Тем не менее, я не чувствую себя очень комфортно с идеей передачи ответственности Ордену за получение частей себя по Id. Моя точка зрения на эту тему такова, что внутри домена мы должны просто общаться с объектами, а не с идентификаторами. Идентификаторы не являются частью вездесущего языка, и я считаю, что они должны жить за пределами домена, например, в Controller.
Я чувствовал бы себя более уверенно с чем-то вроде:
Order order = orderRepository.find(orderId);
OrderLine orderLine = em.find(OrderLine.class, orderLineId);
order.updateQuantity(orderLine, 2);
Хотя мне и не нравится идея взаимодействия напрямую с Entity Manager. Я чувствую, что обхожу обязанности репозитория и агрегированного корня (потому что потенциально я могу напрямую взаимодействовать с Order Line).
Как вы обходите это?
3 ответа
На мой взгляд, нет ничего плохого в этом подходе:
Order order = orderRepository.find(orderId);
order.updateQuantity(orderLineId, 2);
orderLineId
это "местная идентичность". Он специфичен для агрегатного корня и не имеет смысла вне его. Вам не нужно называть это "id", это может быть "номер строки заказа". Из книги Эрика Эвана:
СУЩНОСТИ внутри границы имеют локальную идентичность, уникальную только в пределах АГРЕГАТА.
... только корни AGGREGATE могут быть получены непосредственно с помощью запросов к базе данных. Все остальные объекты должны быть найдены путем обхода ассоциаций.
OrderLineId это что именно? Это не имеет смысла. Вы обновляете количество ПРОДУКТА, и это то, что следует использовать в качестве идентификатора.
Order order = orderRepository.find(orderID);
order.updateQuantity(productID, 2);
Агрегированные корни привязаны к контексту, в вашем контексте ордер - это AR, поэтому можно обновить его напрямую, так как вы напрямую его выставляете, если этот код влияет на другие объекты, которые они должны жить в AR заказа.
Если вам нужен более пуристический подход, вы должны либо создать findByOrderId в AR и загрузить его полностью, либо выставить OrderLine и OrderId в своем приложении (затем используя второй подход).