域驱动设计(DDD)和数据库生成的报告

时间:2016-07-19 16:00:16

标签: database domain-driven-design persistence

我还在调查DDD,但我很想知道一个潜在的陷阱。

根据DDD,聚合根不应该知道持久性,但是这并不意味着整个聚合根最终会在内存中实例化吗?

例如,如果聚合根不应该知道持久性,那么如何要求数据库对大量数据进行分组和求和?

2 个答案:

答案 0 :(得分:3)

  

根据DDD,聚合根不应该知道持久性,但是这并不意味着整个聚合根最终会在内存中实例化吗?

哦不,它比那更糟糕;整个聚合(根和所有从属实体)在内存中实例化加载。基本上,根据定义,您需要加载所有状态才能验证任何更改。

  

例如,如果聚合根不应该知道持久性,那么如何要求数据库对大量数据进行分组和求和?

你不需要聚合根来做到这一点。

域模型的主要作用是通过确保所有写入都遵循业务不变性来确保记录簿的完整性。读取与数据库报告一样,不会更改记录簿,因此您不需要加载域模型。

如果域模型本身需要报告,它通常会定义一个服务提供者接口,用于指定所需的报告,并且持久性组件负责确定如何实现该接口。

答案 1 :(得分:2)

  

根据DDD,聚合根不应该知道持久性,但这是不是意味着整个聚合根最终会在内存中实例化?

聚合根是一致性边界,所以是的,您通常会将整个聚合加载到内存中以强制执行不变量。如果这听起来像是一个问题,那么可能暗示你的聚合太大而且可能需要重构。

  

例如,如果聚合根不应该知道持久性,那么如何要求数据库对大量数据进行分组和求和?

聚合不会要求数据库对数据进行分组和求和 - 通常您会在应用程序服务/命令处理程序中加载聚合。例如:

public class SomeUseCaseHandler : IHandle<SomeCommand>
{
    private readonly ISomeRepository _someRepository;
    public SomeUseCaseHandler(ISomeRepository someRepository)
    {
        _someRepository = someRepository;
    }

    public void When(SomeCommand command)
    {
        var someAggregaate = _someRepository.Load(command.AggregateId);
        someAggregate.DoSomething();
        _someRepository.Save(someAggregate);
    }
}

因此,您的聚合仍然忽略它的持久性。但是,您对ISomeRepository的实现无知,因此可以执行完全加载聚合所需的任何操作。因此,可以在加载聚合时拥有持久性实现组/总和,但更多时候您可能会查询读取模型:

public class SomeUseCaseHandler : IHandle<SomeCommand>
{
    private readonly ISomeRepository _someRepository;
    private readonly ISomeReadModel _someReadModel;

    public SomeUseCaseHandler(ISomeRepository someRepository, ISomeReadModel readModel)
    {
        _someRepository = someRepository;
        _someReadModel = someReadModel;
    }

    public void When(SomeCommand command)
    {
        var someAggregaate = _someRepository.Load(command.AggregateId);
        someAggregate.DoSomethingThatRequiresTheReadModel(_someReadModel);
        _someRepository.Save(someAggregate);
    }
}

您实际上并没有说过您的用例。 :)

[更新]

注意到标题是指数据库生成的报告 - 这根本不会通过您的域模型,它将是一个完全独立的读取模型。 CQRS适用于此