【问题标题】:Is it okay to have more than one repository for an aggregate in DDD?是否可以在 DDD 中为聚合拥有多个存储库?
【发布时间】:2018-04-04 22:53:44
【问题描述】:

我已经阅读了this question about something similar,但它并没有完全解决我的问题。

我有一个应用程序,我需要使用来自 API 的数据。问题是这样做有性能和技术限制。性能限制是显而易见的。技术限制在于 API 不支持我需要进行的一些更精细的查询。

我决定使用 MySQL 作为可查询缓存。

由于我需要从 API 检索的数据不经常更改,我决定每天刷新一次缓存,因此我不需要任何复杂的映射器来检查缓存中是否有数据以及是否没有退回到 API。那是我的第一个设计,但当 API 无法支持我需要进行的大多数查询时,我意识到这不是很实用。

现在每个聚合都有一组两个映射器。一个用于 MySQL,一个用于 API。

我现在的问题是如何从域中隐藏持久性的复杂性,以及我似乎需要多个存储库这一事实。

理想情况下,我应该有一个两个映射器都遵守的界面,但正如之前所披露的那样,这是不可能的。

可以有多个存储库,每个映射器一个吗?

【问题讨论】:

  • 这似乎是做点Context Mapping的好时机。现在您正在考虑将您的应用程序和外部 API 置于同一个限界上下文中,这有点奇怪。

标签: repository domain-driven-design persistence datamapper ddd-repositories


【解决方案1】:

可以在 DDD 中为聚合拥有多个存储库吗?

简短回答:是的。

更长的答案:您不会在 Evans 的原书中找到任何关于多个存储库的建议。正如他所描述的那样,域模型将具有 聚合的一种表示,并且存储库抽象为消费者提供了聚合存储在内存中的集合中的错觉。

很大程度上,这是有道理的——您试图确保对聚合边界内数据的写入是一致的,因此您需要一个单一的权限来进行更改。

但是...没有特别的原因读取需要通过与写入相同的代码路径。欢迎来到 的世界。立即给您的想法是,读取的内存表示可能需要与用于写入的内存表示进行不同的优化。

在更一般的形式中,您会发现您正在建模的概念可能对每个用例有不同的表示。

对于您的情况,有时适合从 RDBMS 读取,有时从 API 读取,有时两者都适合,这不是完全匹配 - 存储库接口对使用者隐藏了实现细节,但您仍然不得不为实现而烦恼。

您可能会关注的一件事是您的要求;每个用例中的数据需要多新鲜? CQRS 模式中经常放松的一个约束是写入的效果可以立即用于读取的想法。要问的一个重要问题是,如果数据还没有被缓存,你能简单地报告“数据不可用”而不点击 API 吗?

如果是这样,那么访问缓存数据的用例只需要一个存储库实现。

【讨论】:

  • 出于不同的原因,我实际上已经在我的应用程序的另一个地方使用了 CQRS。我仍然想使用两个存储库的原因是我仍然可以为每个持久性机制提供一个单一的事实来源。
【解决方案2】:

如果您使用外部 API 来读取和修改数据,您可以在本地缓存它们以加快读取速度,但我会避免使用 域存储库

从域的角度来看,您似乎需要一个服务来查询某些数据(或者只是 CQRS 实现中的一个 Query),您可以使用服务来执行该服务,该服务可以在内部调用一些远程 API 或从本地缓存中读取(mysql,随便)。
当您读取本地缓存时,您可以开发一个存储库来将您的逻辑与 db 实现分离,但这与 域存储库 的概念不同,它只是您的技术实现的一个细节,它具有与您的域无关。
如果远程服务开始提供您需要的查询,您将更改查询的执行方式,调用远程 API 而不是数据库,但您的域模型不应更改。

域存储库用于加载和持久化您的聚合,同时,如果您正在使用外部聚合(在不同的上下文中,子域中),您需要使用服务与它们进行交互。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-30
    • 2012-08-04
    • 2023-02-26
    • 2021-02-27
    • 1970-01-01
    • 2017-11-01
    相关资源
    最近更新 更多