【问题标题】:How can I obtain a DOMAIN-DRIVEN DESIGN architecture using Spring Data JPA?如何使用 Spring Data JPA 获得 DOMAIN-DRIVEN DESIGN 架构?
【发布时间】:2016-11-29 14:05:43
【问题描述】:

我正在开发一个使用 Spring Data JPA 访问数据层的 Spring 应用程序。

所以基本上我有 n 个实体类n 个相关的存储库类 来访问与实体类关联的数据库表的数据,如下所示:

@Repository
@Transactional(propagation = Propagation.MANDATORY)
public interface EntityType1DAO extends JpaRepository<EntityType1, Long> {

   //@Query("FROM Room WHERE accomodation = :id")
   List<EntityType1> findByEntityType1(EntityType1 entityType1);

}

@Repository
@Transactional(propagation = Propagation.MANDATORY)
public interface EntityType2DAO extends JpaRepository<EntityType2, Long> {

   List<EntityType2> findByEntityType2(EntityType2 entityType2);

}

...........................................................................
...........................................................................
...........................................................................

@Repository
@Transactional(propagation = Propagation.MANDATORY)
public interface EntityTypeNDAO extends JpaRepository<EntityTypeN, Long> {

   List<EntityTypeN> findByEntityTypeN(EntityTypeN entityTypeN);

}

所以基本上以这种方式,我有 n 个域类被 **n 个存储库类访问。

我可以将这 n 个领域类划分为属于一个共同概念的子集。

例如,我可以拥有所有属于的实体类,例如:RoomRoomTipology RoomRateRoomPicture 房间概念

所以我将有以下服务类:RoomDAORoomTipologyDAORoomRateDAORoomPictureDAO。 p>

它工作正常,但我想采用更多域驱动设计架构。

所以我发现了这篇关于如何在 Spring 应用程序中获得 DOMAIN-DRIVEN DESIGN 的有趣文章:http://static.olivergierke.de/lectures/ddd-and-spring/

阅读上一篇文章是这样说的:

Repository - Spring 组件,通常是 Spring Data 存储库 界面。可以依赖于实体和值对象,居中 围绕作为聚合根的实体。

具体是什么意思?这意味着我可以创建一个 聚合根 类(例如 RoomAggregation 将我的 RoomRoomTipology 聚合在一起strong>RoomRate 和 RoomPicture 实体类)使用 @Embedded 注释。

或者什么?

在我的应用程序中使用 Spring Data JPA 获得 DOMAIN-DRIVEN DESIGN 的良好架构解决方案是什么?

【问题讨论】:

  • 你读过其他关于 DDD 的东西吗?将整个架构转变基于一篇非常简洁的文章中包含的知识可能不是最好的主意。

标签: java spring spring-data domain-driven-design spring-data-jpa


【解决方案1】:

您不会创建一个新类作为聚合。相反,您选择其中一个现有的。通常它会呈现自己,在您的示例中它可能是Room

因此,您将拥有一个房间存储库(RoomRepositoryRooms 可能)。您可以使用它来保存和加载房间,包括根据您需要的各种标准查找房间。

为了访问(和操作)例如 RoomPicture,您加载 Room 导航到 RoomPicture 操作它并保存您的 JPA 会话,这实际上意味着您正在修改 Room。

如果您选择实体之间的简单导航(@OneToMany 和帮派)或 @Embedded 不受您选择的聚合的影响,除非您没有从聚合到另一个的直接引用。因此,如果您还拥有 Booking 作为 AggregateRoot,那么 Booking 将包含 roomId,您将使用 Room 存储库来查找 Room。

【讨论】:

    【解决方案2】:

    首先,忘记 Spring Data JPA 或任何其他持久性机制。域驱动设计是关于在分析中对域进行建模,而您的特定案例是关于对某种酒店子域进行建模,根本不用担心持久性。这是另一个完全不同的问题,与酒店无关,但与持久性(另一个领域或有界上下文)有关。

    您必须考虑用例而不是概念,这样我们才能识别行为,并通过这种方式检测不变量,使我们能够考虑围绕必须始终保持一致的内容建立边界。

    请记住按照 Vaughn 的建议对小型聚合进行建模,这样您拥有大型聚合的想法听起来并不好。酒店经理可能会实例化一个 Room 来实际代表一个 Room 并给它一个数字和其他一些东西。现在价格和图片怎么样?让我们以价格为例,让我问你,一个房间真的知道它的价格是多少吗?房价不是动态的并且完全受日期等许多其他变量的影响吗?那么为什么要在 Room 聚合中固定一个费率呢?我们说过,在现实世界中,房间不承担此类责任,并且价格受房间边界之外发生的几种情况的影响。因此,Rate 对一个房间来说完全是偶然的,如果我们用哲学术语来讨论,它就不是必需的。

    另一个聚合是 PriceList,它是具有相同名称的聚合根。所以你可以在特定日期询问价目表,房间的价格(标准,豪华,......),它会知道价格:) 根据您对所有这些东西的建模方式,这可能属于作为微服务公开的定价有界上下文,但不要担心 关于它。 PriceList 是另一个与 Room 完全隔离的聚合,并通过其概念标识(即房间号)来引用房间。

    这同样适用于 RoomPicture。在这种特殊情况下,认为处理相册图片的部门/区域/员工可能不是经理,而是具有不同角色并创建具有自己生命周期的房间相册的其他人。

    作为结论,你最终会得到这些聚合:

    房间 价格表 专辑

    请记住,所有这些关联都与房间号(而不是房间)相关联,并且每个关联在不变量周围都有自己的边界。 在一个巨大的应用程序中,您可能会将这些中的每一个都生活在自己的有界上下文中。

    Remember Room 不会对其相册和价格表强制执行任何不变式。

    希望对你有帮助, 塞巴斯蒂安。

    【讨论】:

      【解决方案3】:

      正如@Sebastian 已经很好地阐述的那样,当您对应用程序进行 DDD 时,持久性应该是最不应该担心的事情。 您不要将您的实体与数据库耦合,否则您最终会得到一个非常数据库驱动的应用程序,它与 ddd 混淆了,并且它在干净的代码和美学意义上将无法呈现。 youtube 上有一个很好的演示文稿,名为 Domain Driven Design for Database Driven Mind,请查看。

      其次,您的大多数 DAO 应该重构为值对象,然后您将所有业务逻辑转储到值对象和实体中,最后当您需要担心存储内容时,只需使用数据映射器层即可。

      根据经验,正确完成价值对象将减轻您 90% 的正确应用设计的负担。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-10
        • 2018-06-15
        • 2019-11-18
        • 1970-01-01
        • 1970-01-01
        • 2021-12-01
        相关资源
        最近更新 更多