CQRS 部门域实体的哪些属性
What properties on Department domain entity for CQRS
我是第一次尝试 CQRS,需要一些建议。
在我的业务中,部门可以重命名。为此,我发送了一个由命令处理程序捕获的 RenameDepartment 命令。然后这个处理程序将调用 Department 实体上的重命名方法,这是否应该对实体做任何事情,即更新名称 属性?由于该名称仅供查看之用,我想我应该做的就是发送一个 DepartmentRenamed 事件并更新相应的 ViewModel,我的想法是否正确?
提前致谢
CQRS 将读取责任和写入责任分成不同的部分:
- 编写存储、事件存储以保存您域中发生的所有事件
- 读取存储,以保留根据来自写入模型的事件存储的事件流增量构建的投影。
你做对了,因为你的 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
}
}
我是第一次尝试 CQRS,需要一些建议。
在我的业务中,部门可以重命名。为此,我发送了一个由命令处理程序捕获的 RenameDepartment 命令。然后这个处理程序将调用 Department 实体上的重命名方法,这是否应该对实体做任何事情,即更新名称 属性?由于该名称仅供查看之用,我想我应该做的就是发送一个 DepartmentRenamed 事件并更新相应的 ViewModel,我的想法是否正确?
提前致谢
CQRS 将读取责任和写入责任分成不同的部分:
- 编写存储、事件存储以保存您域中发生的所有事件
- 读取存储,以保留根据来自写入模型的事件存储的事件流增量构建的投影。
你做对了,因为你的 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
}
}