在 CQRS 的写入端从数据库中读取数据
Reading data from database on Write Side in CQRS
背景:
解释 CQRS 的图表通常会明确区分读写路径和单向数据流,如本例所示(来源:Demystified CQRS) :
问题:
我想澄清一下,
如果后端的命令执行需要数据库中的一些数据,
- "write side" 是否应该具有一些从写数据库读取的能力?
- 或者它应该完全依赖 "read side" 进行任何读取?
- 或者命令应该包含调用者提供的所有需要的数据才能完成?
@埃德加斯,
根据我的经验,您的命令处理程序可以 "read" 来自您 "read-only data readers" 的数据。与您用于模型读取的相同。
public class CreateNewSantaCommandHandler: ICommandHandler<CreateNewSantaCommand>
{
public IReadOnlyRepo<SomeDTO> readOnlyRepo;
public ISantaRepo<Santa> santaRepo;
// Inject the repos in the constructor, etc. You get the idea.
public void Execute(CreateNewSantaCommand command)
{
var suit = readOnlyRepo.GetSuit(command.suitType) //Data you need
var santa = Santa.New(command); //Factory method;
santa.GetDressedPlease(suit);
santaRepo.Add(santa);
santa.Save() // this shouldn't be here. Usually higher level. UOW.
}
}
有道理吗?
should a "write side" have some read capabilities from write database?
可能 - 加载将成为 运行 命令的实体的最直接方法是从 "write database" 读取其状态。例如,在事件源架构中,更新事件源实体的命令通常通过从写入模型加载该实体的历史记录、从该历史记录中重新组合实体、评估命令以及将新更改附加到历史记录来处理。
读取有关不处理命令的实体的状态是另一回事——ddd词汇在这里有帮助;您正在修改的状态恰好属于一个聚合,聚合之外的状态应该传递给模型,而不是获取,只要有可能。
这可能意味着远程客户端需要提供数据,或者可能意味着处理命令的应用程序获取所需的读取模型并提供答案。有许多不同的问题可以促使您在此处做出选择
- 如果客户端在生成命令时使用的读取模型与应用程序在处理命令时使用的视图明显不同,则存在一些风险。
- 保持稳定 API 允许您自由地重新设计模型中的聚合边界,而无需更新客户端)。
所以没有一个最佳答案,只是在不同的关注点之间进行权衡。
最近出现了后者的一个例子——如果您的业务模型要求某些命令需要特定用户的权限,那么我们不应该从表面上接受来自客户端的命令;我们需要应用程序来验证命令发出者的身份,然后将该身份的表示传递给模型,以便它可以确定要采取的行动。
背景:
解释 CQRS 的图表通常会明确区分读写路径和单向数据流,如本例所示(来源:Demystified CQRS) :
问题:
我想澄清一下,
如果后端的命令执行需要数据库中的一些数据,
- "write side" 是否应该具有一些从写数据库读取的能力?
- 或者它应该完全依赖 "read side" 进行任何读取?
- 或者命令应该包含调用者提供的所有需要的数据才能完成?
@埃德加斯,
根据我的经验,您的命令处理程序可以 "read" 来自您 "read-only data readers" 的数据。与您用于模型读取的相同。
public class CreateNewSantaCommandHandler: ICommandHandler<CreateNewSantaCommand>
{
public IReadOnlyRepo<SomeDTO> readOnlyRepo;
public ISantaRepo<Santa> santaRepo;
// Inject the repos in the constructor, etc. You get the idea.
public void Execute(CreateNewSantaCommand command)
{
var suit = readOnlyRepo.GetSuit(command.suitType) //Data you need
var santa = Santa.New(command); //Factory method;
santa.GetDressedPlease(suit);
santaRepo.Add(santa);
santa.Save() // this shouldn't be here. Usually higher level. UOW.
}
}
有道理吗?
should a "write side" have some read capabilities from write database?
可能 - 加载将成为 运行 命令的实体的最直接方法是从 "write database" 读取其状态。例如,在事件源架构中,更新事件源实体的命令通常通过从写入模型加载该实体的历史记录、从该历史记录中重新组合实体、评估命令以及将新更改附加到历史记录来处理。
读取有关不处理命令的实体的状态是另一回事——ddd词汇在这里有帮助;您正在修改的状态恰好属于一个聚合,聚合之外的状态应该传递给模型,而不是获取,只要有可能。
这可能意味着远程客户端需要提供数据,或者可能意味着处理命令的应用程序获取所需的读取模型并提供答案。有许多不同的问题可以促使您在此处做出选择
- 如果客户端在生成命令时使用的读取模型与应用程序在处理命令时使用的视图明显不同,则存在一些风险。
- 保持稳定 API 允许您自由地重新设计模型中的聚合边界,而无需更新客户端)。
所以没有一个最佳答案,只是在不同的关注点之间进行权衡。
最近出现了后者的一个例子——如果您的业务模型要求某些命令需要特定用户的权限,那么我们不应该从表面上接受来自客户端的命令;我们需要应用程序来验证命令发出者的身份,然后将该身份的表示传递给模型,以便它可以确定要采取的行动。