Domain driven design 聚合根目录中包含的实体如何保存在DDD中?

Domain driven design 聚合根目录中包含的实体如何保存在DDD中?,domain-driven-design,aggregate,ddd-repositories,aggregateroot,dddd,Domain Driven Design,Aggregate,Ddd Repositories,Aggregateroot,Dddd,在阅读了大量文章后,我意识到如果一个概念/上下文存在聚合根,那么我们需要为整个概念/上下文建立一个存储库 如果是这样,我看到内部实体将不会有任何存储库。如果是,这些内部实体是如何保存到数据库的 我在聚合根下有许多内部实体。因此,如果我想知道是否需要将所有内部实体保存在聚合根存储库下,它将变得臃肿。请建议在这种情况下可以做什么 此外,我的内部实体将在持久性级别访问它们自己的每个表。如果不允许我以这种方式存储内部实体,请更正 示例 我想我有一个餐厅作为一个聚合根。它可以对名为Review的实体进行分

在阅读了大量文章后,我意识到如果一个概念/上下文存在聚合根,那么我们需要为整个概念/上下文建立一个存储库

如果是这样,我看到内部实体将不会有任何存储库。如果是,这些内部实体是如何保存到数据库的

我在聚合根下有许多内部实体。因此,如果我想知道是否需要将所有内部实体保存在聚合根存储库下,它将变得臃肿。请建议在这种情况下可以做什么

此外,我的内部实体将在持久性级别访问它们自己的每个表。如果不允许我以这种方式存储内部实体,请更正

示例
我想我有一个餐厅作为一个聚合根。它可以对名为Review的实体进行分组。一家餐馆有一个评论,没有它就不可能存在

在这里,如果Review是一个内部实体,并且一家餐厅可能有许多评论,那么评论将保存在一个单独的表中。但由于餐馆聚合根只有一个餐馆存储库,因此如何/在何处处理保存评论

如果是这样,我看到内部实体将不会有任何存储库。如果是,这些内部实体是如何保存到数据库的

聚合表示一致性边界。如果一个实体为聚合所拥有,并且是确保一致性所必需的,那么它应该与聚合根保持一致

因此,如果我想知道是否需要将所有内部实体保存在聚合根存储库下,它将变得臃肿

是的,是的。如果这是一个真正的问题,你可以考虑使用ORM。ORM将在内存中维护以聚合根为根的图形,并确保在必要时保留更改

此外,我的内部实体将在持久性级别访问它们自己的每个表。如果不允许我以这种方式存储内部实体,请更正


尝试将您的域与您的持久性策略分开考虑。您有一个映射到关系模式的域模型。关系模式不应驱动域的设计

我想补充CPerson的回答

这种不涉及背景的讨论往往毫无意义。每种情况都是特定于上下文的,很少归结为持久性问题

在上述案例中,我永远不会将Review作为餐厅聚合中的一个实体进行建模。这不是持久性问题,而是建模问题

有一些DDD书籍,我相信阅读一些博客文章不足以理解DDD的战略和战术模式。其中一种模式实际上是聚合模式。简言之,聚合是一致性边界。聚合始终是特定于上下文的(与其他任何内容一样)

如果您正在对餐厅管理系统或食品配送系统进行建模,则可能需要在单独的上下文中进行评审。没有“餐厅语境”这样的语境。这就是有界上下文模式的全部要点。在您的示例中,它可能是餐厅评论上下文。评论的内容与食物、开放时间和餐桌预定无关

如果你像TripAdviser一样建模,基本上你只有评论。在这种情况下,审查或多或少与正在审查的内容无关。那么,你的模式就完全不同了

评论的数量在不断增长,因此将所有评论作为实体放到某个集合中没有多大意义。同样,聚合是一致性边界。如果另一篇评论是一颗星,你会说评论不能发布吗?我不这么认为。关于评论,你试图在餐馆总量中保护的不变量是什么?您是否需要根据这些评论限制评论次数以改变餐厅的状态?我认为情况并非如此。因此,审查本身可以是一个集合,因为所有审查都是完全独立的


评论聚合中的餐厅可以是一个简单的值对象,它保存着餐厅id。在构造这个值对象时,您应该确保给定的餐厅确实存在并开放供评论。当餐厅消失时,您确实需要清除评论。但它也是特定于上下文的。餐厅可能会关门,但你还是会保留评论。

我同意其他答案中的一些观点,即你可能不想这样做,但我认为你的问题本身尚未得到回答。举个例子,这是非常好的

下面是:

您不为实体创建存储库(如在DDD存储库中),只为聚合根创建。 因此,在您的示例中,应用程序层可能类似于:

Restaurant restaurant = restaurantRepository.findById(23)
restaurant.addReview(review)
restaurantRepository.save(restaurant)
还要注意,操作是在聚合根上完成的。 所以一般来说,应用层中的命令通常是:加载聚合、对其执行操作、保存它

将聚合保存为一个整体,并将实体与其一起保存。 存储库后面发生的事情取决于您的基础结构。当然,因为存储库属于域,所以我们不关心那里的基础设施

然后是基础架构层的实现(这些只是一些示例):

  • 在documentDB中,您将有一个存储库的实现,它只是将文档作为一个整体保存到DB中。(这里的文档存储和DDD非常匹配,因为aggregate=Document)
  • 如果要在一个简单的文本文件中将聚合序列化到磁盘,则可能会有一个存储库实现,其中每个实体都有一个序列化器,即值对象来执行序列化
  • 如果您有一个RDBMS