DDD声明您应该只通过其聚合根访问实体。例如,假设你有一个聚合根X,它可能有一个 lot 的子Y实体。现在,对于某些情况,您一次只关心这些Y实体的子集(可能您正在分页列表中显示它们等等。)
然后可以实现存储库,以便在这种情况下它返回不完整的聚合? IE浏览器。一个X对象谁只有Ys集合只包含我们感兴趣的Y实例,而不是所有它们?例如,这可能导致X上的方法执行一些涉及Ys的计算不能按预期运行。
这是否表明有问题的Y实体应该被视为提升为聚合根?
我目前的想法(在C#中)是利用LINQ的延迟执行,以便我的X对象具有IQueryable来表示它与Y的关系。这样,我可以通过过滤来进行透明的延迟加载......但是这与ORM一起使用(在我的情况下,Linq到Sql)可能有点棘手。
还有其他聪明的想法吗?
答案 0 :(得分:6)
我认为带有子实体的 lot 的聚合根是代码气味,或者如果你愿意,可以认为是DDD气味。 :-)一般来说,我看两个选项。
答案 1 :(得分:4)
Jimmy Nilsson在他的书中暗示,您可以阅读其中部分内容的快照,而不是阅读完整的聚合。但是您不应该能够将快照类中的更改保存到数据库中。
Jimmy Nilsson's book第6章:准备基础架构 - 查询。第226页。
答案 2 :(得分:1)
你真的在问两个重叠的问题。
你的问题的标题和前半部分是哲学/理论的。我认为仅通过“聚合根”访问实体的原因是抽象出你所描述的各种实现细节。通过聚合根进行访问是一种通过拥有可信访问点来降低复杂性的方法。通过遵守惯例,您可以消除摩擦/模糊/不确定性。无论它是如何在根目录中实现的,你只要知道当你要求一个实体它就会存在。我不认为这个视角排除了你所描述的“过滤后的存储库”。但是要为开发人员提供pit of success,应该无法实例化存储库而不明确其“过滤性”;同样,如果可以对存储库实例进行共享访问,则在调用者中进行编码时,“过滤性”应该是显式的。
问题的后半部分是关于特定平台的实施。不确定为什么你提到延迟执行,我认为这与过滤问题完全正交。使用LINQ实现过滤本身可能有点棘手。也许不是内联Where lambdas,而是设置它们的集合并根据您需要的过滤器选择一个。
答案 3 :(得分:0)
你被允许,因为代码无论如何都会被编译,但是如果你要进行纯DDD设计,你就不应该有不完整的对象实例。
如果您害怕加载一个只会使用其子项实体的一小部分的巨大对象,您应该查看LazyLoading。
LazyLoading会延迟加载您决定延迟加载的内容,直到访问它们为止。一旦代码调用它们,它们就会使用回调来调用加载方法。
答案 4 :(得分:0)
然后可以实现存储库,这样在这种情况下 返回不完整的汇总?
一点也不。聚合是一个跨国边界,可以更改您的系统状态。切勿使用聚合查询数据。将系统分为写入和读取两面。 (了解有关CQR和CQRS的信息)。当我们认为基于“ CRUD”时,我们会基于某些资源来实施我们的系统。假设您有“约会”合计。认为“ Crudish”意味着我们应该实现用例Create,Update,Delete,GetAll约会。这意味着应该为GetAll返回Appointment []。当您认为基于用例的(HexagonalArchitecture)时,您的用例将是ScheduleAppointment,RescheduleAppointment,CancelAppointment。但对于查询端,它可以是:/ myCalendar。我们返回ClientCalendar对象中特定用户的所有约会。为查询端创建单独的DTO。切勿为此目的使用聚合。