DDD声明您应该只通过其聚合根访问实体。 例如,假设你有一个聚合根X,它可能有很多子Y实体。 现在,对于某些情况,您一次只关心这些Y实体的子集(可能您正在将它们显示在分页列表中或其他任何内容中)。

那么实现存储库是否可以,以便在这种情况下它返回一个不完整的聚合? IE浏览器。 一个X对象谁只有Ys集合只包含我们感兴趣的Y实例而不是所有它们? 例如,这可能导致X上的方法执行一些涉及Ys的计算不能按预期运行。

这或许表明有问题的Y实体应被视为提升为聚合根吗?

我目前的想法(在C#中)是利用LINQ的延迟执行,以便我的X对象具有IQueryable来表示它与Y的关系。这样,我可以通过过滤实现透明的延迟加载...但是让它工作使用ORM(在我的情况下Linq到Sql)可能有点棘手。

还有其他聪明的想法吗?

===============>>#1 票数:6

我认为具有很多子实体的聚合根是代码气味,或者如果你愿意的话,会有DDD气味。 :-)一般来说,我看两个选项。

  1. 将您的聚合拆分为许多较小的聚合。 这意味着我的原始设计不是最优的,我需要识别一些新的实体。
  2. 将您的域拆分为多个有界上下文。 这意味着有一组特定的场景使用聚合中实体的公共子集,而有其他一组场景使用不同的子集。

===============>>#2 票数:4

Jimmy Nilsson在他的书中暗示,您可以阅读其中部分内容的快照,而不是阅读完整的聚合。 但是您不应该能够将快照类中的更改保存到数据库中。

Jimmy Nilsson的书第6章:准备基础设施 - 查询。 第226页。

快照模式

===============>>#3 票数:1

你真的在问两个重叠的问题。

  1. 你的问题的标题和前半部分是哲学/理论的。 我认为仅通过“聚合根”访问实体的原因是抽象出你所描述的各种实现细节。 通过聚合根进行访问是一种通过拥有可信访问点来降低复杂性的方法。 通过遵守惯例,您可以消除摩擦/模糊/不确定性。 无论它是如何在根目录中实现的,你只要知道当你要求一个实体它就会存在。 我不认为这个视角排除了你所描述的“过滤后的存储库”。 但是为了让开发人员陷入成功的陷阱,应该不可能实例化存储库而不明确其“过滤性”; 同样,如果可以对存储库实例进行共享访问,则在调用者中进行编码时,“过滤性”应该是显式的。

  2. 问题的后半部分是关于在特定平台上的实现。 不确定为什么你提到延迟执行,我认为这与过滤问题完全正交。 使用LINQ实现过滤本身可能有点棘手。 也许不是内联Where lambdas,而是设置它们的集合并根据您需要的过滤器选择一个。

===============>>#4 票数:0

你被允许,因为代码无论如何都会被编译,但是如果你要进行纯DDD设计,你就不应该有不完整的对象实例。

如果您害怕加载一个只使用其子实体的一小部分的巨大对象,您应该查看LazyLoading。

LazyLoading延迟加载任何你决定延迟加载的内容,直到它们被访问为止。 一旦代码调用它们,它们就使用回调来调用加载方法。

===============>>#5 票数:0

那么实现存储库是否可以,以便在这种情况下它返回一个不完整的聚合?

一点也不。 Aggregate是一个改变系统状态的跨国界限。 切勿使用聚合来查询数据。 将系统拆分为写入和读取端。 (阅读关于CQR和CQRS)。 当我们认为“CRUD”为基础时,我们基于一些资源实现我们的系统。 假设您有“预约”汇总。 思考“Crudish”意味着我们应该实现用例创建,更新,删除,GetAll约会。 这意味着应该为GetAll返回Appointment []。 当您认为基于usecase时,(HexagonalArchitecture)您的用例将是ScheduleAppointment,RescheduleAppointment,CancelAppointment。 但对于查询方面,它可以是:/ myCalendar。 我们返回ClientCalendar对象中特定用户的所有约会。 为查询方创建单独的DTO。 切勿将聚合物用于此目的。

  ask by Fredrik Kalseth translate from so

未解决问题?本站智能推荐: