数据库和聚合根的存储库模式

Posted

技术标签:

【中文标题】数据库和聚合根的存储库模式【英文标题】:Repository pattern for database and aggregate root 【发布时间】:2014-02-24 09:57:25 【问题描述】:

我正在尝试理解“聚合根”的概念。

让我感到困惑的一件事是,我不应该直接访问子实体而不访问其聚合根。例如,假设我有一个计算机实体和一个硬件实体。

据我了解,我不应该直接直接访问硬件实体。我应该通过它的聚合根访问一个硬件实体,它是一个计算机实体。

假设我有一个控制器,它使用存储库并查询计算机实体。

class Controller_Test 

    public function loadHardware($computerRepository)
    
        $computer = $computerRepository->find_by_id(1);
        $hardware = $computer->hardware; // lazy load
    

如果我使用的是数据库,我最终会执行两个查询。一个用于计算机,另一个用于硬件。

在我的存储库中使用“loadComputerWithHardware”来保存查询次数不是很有意义吗?是否违反 DDD 规则(通过连接两个表来同时查询计算机和硬件)?

【问题讨论】:

【参考方案1】:

没有人强迫您使用延迟加载,当您有复杂的实体图时这样做很常见,但如果它更适合您,您可以使用急切加载。请注意,即使您使用延迟加载,这也可以对域模型透明。

让我感到困惑的一件事是,如果不访问子实体的聚合根,我不应该直接访问子实体。

这个想法是聚合是其图中所有实体的唯一负责人,因此,在其图中执行的所有操作都应该通过他,甚至查询单个节点(子实体)。

在我的存储库中使用“loadComputerWithHardware”来保存查询次数不是很有意义吗?

好吧,这取决于您,但如果您不小心,您最终可能会弄乱您的界面。我会坚持使用loadComputer,并让您的数据存储库的每个实现来决定何时更好地进行急切或延迟加载。

是否违反 DDD 规则(通过连接两个表来同时查询计算机和硬件)?

不,“连接两个表”不是域概念,它是数据层问题,应该将它们解耦。

【讨论】:

【参考方案2】:

控制器对硬件一无所知。它只知道计算机。存储库负责加载计算机所需的所有内容。如果您需要从控制器的角度对硬件的引用,它可能本身就是一个聚合。

【讨论】:

如果我想通过一次查询获得一台带有硬件的计算机怎么办?我的问题是,使用“loadComputerWithHardware”或“findWithHardware”是否违反? 如果硬件是聚合的一部分,那么它应该由计算机的存储库检索。

以上是关于数据库和聚合根的存储库模式的主要内容,如果未能解决你的问题,请参考以下文章

减少存储库以聚合根

什么是聚合根?

域驱动设计:如何访问聚合根的子节点

存储库模式:如何延迟加载?或者,我应该拆分这个聚合吗?

基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则

一系列简单的聚合根问题(领域驱动设计)