Language agnostic DDD:通过其标识引用聚合根中的实体
我一直在寻找正确的方法来引用位于聚合根中的实体,而我们只从URL参数获取它们的标识。我问了一个以价值对象为中心的例子,所以我从另一个例子开始 假设我们要在Language agnostic DDD:通过其标识引用聚合根中的实体,language-agnostic,domain-driven-design,entity,identity,aggregateroot,Language Agnostic,Domain Driven Design,Entity,Identity,Aggregateroot,我一直在寻找正确的方法来引用位于聚合根中的实体,而我们只从URL参数获取它们的标识。我问了一个以价值对象为中心的例子,所以我从另一个例子开始 假设我们要在订单中修改订单行: 用户进入一个页面,可以看到订单摘要及其所有订单行 用户单击订单行旁边的编辑按钮 他被引导到编辑订单行?orderId=x&orderLineId=y 现在,如果我需要更新订单行中的数量,我可以执行以下操作: Order order = orderRepository.find(orderId); order.update
订单
中修改订单行
:
- 用户进入一个页面,可以看到订单摘要及其所有订单行
- 用户单击订单行旁边的编辑按钮
- 他被引导到
编辑订单行?orderId=x&orderLineId=y
Order order = orderRepository.find(orderId);
order.updateQuantity(orderLineId, 2);
然而,我不太赞成将责任交给通过Id检索自身部分的订单。我对这个主题的看法是,在域内,我们应该只与对象交谈,而不要与Id交谈。ID不是无处不在的语言的一部分,我相信它们应该存在于域之外,例如控制器中
我会对这样的事情更有信心:
Order order = orderRepository.find(orderId);
OrderLine orderLine = em.find(OrderLine.class, orderLineId);
order.updateQuantity(orderLine, 2);
尽管我也不喜欢与实体经理直接互动的想法。我觉得我绕过了存储库并聚合了根职责(因为我可以直接与订单行交互)
如何解决这一问题?聚合根绑定到上下文,在您的上下文中,顺序是AR,因此可以直接更新它,因为您直接公开它,如果该代码影响其他实体,它们应该以AR顺序存在
如果您想要更纯粹的方法,您必须在AR中创建findByOrderId并完全加载它,或者在应用程序中公开OrderLine和OrderId(然后使用第二种方法)。我认为这种方法没有错:
Order order = orderRepository.find(orderId);
order.updateQuantity(orderLineId, 2);
orderLineId
是一个“本地标识”。它是特定于聚合根的,在它之外没有意义。您不必称之为“id”,它可以是“订单行号”。书中:
边界内的实体具有本地标识,仅在内部唯一
总量
…只有聚合根可以通过数据库查询直接获得。必须通过遍历关联找到所有其他对象
OrderLineId到底是什么?这没有意义。您正在更新产品的数量,这就是应该用作id的内容
Order order = orderRepository.find(orderID);
order.updateQuantity(productID, 2);
我认为Benjamin的问题是关于从聚合根目录导航到他想要更新的订单行的最佳方式。让应用程序代码在订单行中迭代似乎与应用程序代码有冲突。感谢您的澄清,我承认我没有使用上面发布的“仅在聚合中唯一”Dmitry,现在想知道我是否遇到过这样的实现。我同意-orderLineId不一定是指您的DB id,它可以是唯一标识此单个聚合中的订单的任何内容(行的序号或orderNo/LineNo形式的聚合代码)。按此标识符查找特定行是订单的责任。这种方法不会影响AR的接口吗?如果AR只有2个实体,每个实体有2个方法,AR需要4个方法来支持实体,这是理想的方法吗?这取决于,有人会说,当你有这么大的总量时,你已经有问题了。这可能只是一个迹象,表明您需要重新考虑对较小集合的设计,请参见:这是一个相关的反对意见,尽管在我们的应用程序中,您的购物车中可能有多次相同的产品,选择了不同的选项(考虑一件绿色t恤和一件红色t恤;如果我想专门更新绿色t恤的数量,我不想通过完整的选项数组来匹配正确的订单行:颜色、尺寸……因此,在这一点上传递
orderLineId
对我来说最有意义).很公平。虽然我可能仍然会选择更自然的密钥,例如productID+任何其他使其唯一的密钥。但当然,OrderLineId仍然有效。