Onion/Hexagonal 架构中的数据库外部化

Database externalization in Onion/Hexagonal architecture

我正在考虑使用 onion/hexagonal 架构模式编写应用程序。我被困在数据库外部化上。

我的应用需要进行一些复杂的数据查询来完成用例。 我有两个聚合 "A" 和 "B",它们是相关的。为了实现 UseCase1,我需要获取所有具有与给定值匹配的属性的 "A" 以及与具有与其他值匹配的属性的 "B" 相关的附加信息。为了完成 UseCase2,我需要做一些其他的 "query"。我计划创建一个存储库接口 f.e。 ARepository,它将数据库访问细节与域逻辑隔离开来。由于过滤规则是域规则,因此它们不能是存储库 class.

的实现细节

我的疑惑:

  1. ARepository 实现可以将一些 SQL 连接到 "B" 表吗?
  2. 是否可以设计一些通用的过滤条件对象并且每个用例将创建自己的条件并使用它传递给 ARepository::filterByCriteria()?这是一份好合同吗?
  3. 是否可以在 ARepository 中为每个 UseCase 创建专用方法? (我相信以后会有很多名字描述用例的过滤方法)

欢迎提出任何其他想法

用例示例:

UseCase1 - 从 "A"s:

创建报告

用例 2 - 将 "A" 导出到外部系统:

  1. Is it ok that ARepository implementation makes some SQL joins to "B" tables?

是的,一个聚合可以加载与其他聚合共享的片段。

  1. Is it ok to design some generic filter criteria object and each UseCase will create own criteria and use it to pass to ARepository::filterByCriteria()? Is it a good contract?

据我所知,存储库的设计没有租户,但可以使用几种不同的 techniques/patterns。您应该找到您正在从事的 language/environment 中使用的技术,然后选择最适合您需要的技术。

  1. Is it ok to create dedicated methods in ARepository for each UseCase? (I'm affraid that in the future there will be plenty of filter methods with names describing usecases)

是的,这是一个经常使用的有效模式。

作为参考,你应该看看CQRS。您可以拥有一个不同于域模型的单独报告模型,这种方法有一些有趣的好处和后果。看看吧!

此外,在处理 DDD 时,请记住限界上下文非常重要,域层应该是业务及其交互的表达表示。在发布 DDD 问题时,您可能应该始终提供限界上下文。我这么说的原因是因为无法知道您提供的用例与您的业务有何关系。它们甚至可能根本不属于域层。

举个例子,假设您有用例 A:用户可以 select 发票模板应用于他们生成的发票。

如果您是发票服务,这个用例很可能属于您的领域层,我想 Invoice 可能是聚合根。

如果您是地毯清洁服务商,这个用例可能 UI 毫无意义,根本不属于您的领域层。在那种情况下,这可能更适合单独在 UI 下或可能在应用程序服务下。

所有这些都是说用例可能属于也可能不属于您的领域层,具体取决于您的业务。在 DDD 中,上下文就是一切。

您的用例中存在重复。如果他们很好地描述了企业思考和谈论系统的方式,那么为他们提供专门的入口点是可以的。然而,重要的是要确保系统地消除其实施中的重复。

我经常看到的一个问题是有太多的开发人员实现了类似的用例,使用复制和粘贴的方式,没有花时间就它们进行交流和重构。我总是 运行 在新的(对我而言)代码库上使用克隆检测器。