CQRS 部门域实体的哪些属性

What properties on Department domain entity for CQRS

我是第一次尝试 CQRS,需要一些建议。

在我的业务中,部门可以重命名。为此,我发送了一个由命令处理程序捕获的 RenameDepartment 命令。然后这个处理程序将调用 Department 实体上的重命名方法,这是否应该对实体做任何事情,即更新名称 属性?由于该名称仅供查看之用,我想我应该做的就是发送一个 DepartmentRenamed 事件并更新相应的 ViewModel,我的想法是否正确?

提前致谢

CQRS 将读取责任和写入责任分成不同的部分:

  1. 编写存储、事件存储以保存您域中发生的所有事件
  2. 读取存储,以保留根据来自写入模型的事件存储的事件流增量构建的投影。

你做对了,因为你的 RenameDepartmentCommandHandler 会处理命令 RenameDepartmentCommand:

public void RenameDepartmentCommandHandler(RenameDepartmentCommand command)
{
    // repository is injected in for us during command handler instantiation
    var dept = this.repository.GetByDeptName(command.DepartmentName);
    dept.RenameDepartment(command.NewDepartmentName);
    this.repository.Save(dept);

    // the repository will save all of the events, once committed
    // a separate piece of code running in the background will
    // listen for new events from the the event-store and dispatch
    // them to anyone who may be listening
}

需要通过持久化事件在写入模型中更新实际实体,这是您的唯一真实来源。您不仅会更新读取模型,还会更新写入模型。

在写入模型持久化事件后,它将(在未来的某个时间点)分派给读取模型。

读模型是写模型的从属。因为它是一个slave,它会最终保持一致(对于使用独立基础设施且不使用分布式事务的读写模型)......最终一致并不意味着有问题,通常是延迟(10ms到秒甚至分钟)对大多数问题空间来说都是可以接受的。

因此您的实体将如下所示:

public class Department : AggregateBase
{
    // this class derives from jOliver's CommonDomain project
    // only useful if using C# - there will be similar
    // event sourcing infrastructure projects for different
    // languages

    public string Name { get; protected set; }
    // all other properties go here

    public void RenameDepartment(public newName)
    {
        // the DepartmentRenamed is an immutable class taking the
        // current name and new name as constructor parameters          
        RaiseEvent(new DepartmentRenamed(this.Name, newName));
    }

    protected void Apply(DepartmentRenamed evnt)
    {
        this.Name = event.NewName;
    }
}

你读取的模型投影是这样的:

public class DeptNameListProjection : IEventHandler<DepartmentRenamed>
{
    public void Handle(DepartmentRenamed evntFromEventStore)
    {
        var department = this.readStore.Find(evntFromEventStore.OldName);
        // write it, depends on your infrastructure
        // normally a SqlCommand or similar is fine here, I try and avoid
        // using an ORM as imho flat tables make more sense for read models
    }
}