5

我正在尝试将我的应用程序从每个实体的存储库重构为每个聚合根的存储库。

一个基本的例子是我有一个 Cars 的实体根。汽车有租赁合同。据我所知,没有汽车就没有合同,因此汽车是总根。

我正在尝试实现一个用户视图,它将显示系统中的每个合同(根实体的所有子实体)。在重构之前,我可以去我的合约存储库并获取所有。由于合同存储库已被删除(因为它不是根),我现在需要将所有汽车从我的存储库中取出,然后获取他们的所有合同。

我的存储库有接口

public interface ICarRepository
{
    IQueryable<Car> All { get; }
    IQueryable<Car> AllIncluding(params Expression<Func<Car, object>>[] includeProperties);
    Car Find(long id);
    void InsertOrUpdate(Car car);
    void Delete(long id);
    void Save();
}

我想创建一个 ICarManagementService 并让它有一个 GetAllContracts 方法(可能带有过滤器参数)。这是否意味着获得我需要的所有合同,将所有汽车实体与他们的合同一起取出,然后检索与租赁合同相关的每个实体并过滤它们?

然后我可以将这些传递给控制器​​并像以前一样自动映射合同。

这是最佳实践吗?

谢谢

格雷姆

4

2 回答 2

5

据我所知,没有汽车就没有合同,因此汽车是总根。

这不一定是真的。“不存在”不足以让实体成为聚合根的一部分。考虑经典的订单处理领域。您有一个作为聚合根的订单。您还有一个作为聚合根的客户。没有客户订单就不能存在,但这并不意味着订单是客户集合的一部分。在一个聚合内的 DDD 实体中,可以引用其他聚合根。来自DDD 书

AGGREGATE 中的对象可以保存对其他 AGGREGATE 根的引用。

聚合是一个生命周期和数据交换单元。它本质上是一组强制执行不变量的对象。如果您有多个用户同时更改域,则这是您想要锁定的内容。

回到您的问题,我的理解是,该域类似于出租/租赁汽车/卡车/豪华轿车/推土机。我认为 HireContract 可能不是 Car 聚合的一部分,因为它们可能有不同的生命周期,而 HireContract 本身就有意义,没有 Car。它似乎更像是订单-产品关系,这也是两个不同聚合相互引用的经典示例。业务需要查看“所有合同”这一事实也证实了这一理论。他们可能不认为 Car 包含所有合同。如果这是真的,那么您需要保留您的 ContractsRepository。

在不相关的说明中,您可能有兴趣阅读有关存储库界面设计的答案。

于 2011-09-18T12:38:35.163 回答
4

将读/查询的概念与写/命令分开,按照 CQRS 的指导,最好通过分离由只读查询组成的读模型和由执行某些逻辑的命令组成的写模型来设计应用程序在域模型上。

因此查询所有聚合根或创建自定义查询以连接数据集不是域存储库的良好候选者,而是将这些查询放入读取存储库(或更好地命名为 Finders)。

如果您发现自己想要查询对象集合以执行某些域逻辑,则表明您必须抽象该集合并将其放入聚合根中以封装它们并使业务操作或方法作用于它们.

查看(http://moh-abed.com/2011/09/13/pure-old-ddd-with-a-twist-from-cqrs/)和(http://simon-says-architecture.com/ 2011/08/23/存储库)

于 2011-09-18T11:48:03.037 回答