DDD 中的聚合可以有多个存储库吗?

Is it okay to have more than one repository for an aggregate in DDD?

我读过 this question about something similar 但它并没有完全解决我的问题。

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

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

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

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

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

理想情况下,我会拥有一个两个映射器都遵守的接口,但如前所述,这是不可能的。

是否可以拥有多个存储库,每个映射器一个?

Is it okay to have more than one repository for an aggregate in DDD?

简答:是。

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

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

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

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

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

您可能会看的一件事是您的要求;每个用例中的数据需要多新鲜? CQRS 模式中经常放宽的约束是写入的效果可立即用于读取的想法。要问的重要问题是,如果数据尚未缓存,您是否可以简单地报告 "data not available" 而无需点击 API?

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

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

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

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