让我们以一个简单的“注册帐号”的例子,这里是流量:CQRS事件采购:验证用户名的唯一性
- 用户访问网站
- 点击“注册”按钮,填写表格,点击“保存”按钮
- MVC控制器:验证用户名的唯一性由ReadModel
- RegisterCommand阅读:再次验证用户名的唯一性(这里是问题)
当然,我们可以通过读取MVC控制器中的ReadModel来验证UserName的唯一性,以提高性能和用户体验。但是,我们仍然需要在RegisterCommand中再次验证唯一性,显然,我们不应该在Commands中访问ReadModel。
如果我们不使用事件采购,我们可以查询领域模型,所以这没有问题。但是如果我们使用事件采购,我们无法查询域模型,所以我们如何验证RegisterCommand中的用户名唯一性?
说明:用户类具有Id属性,UserName不是User类的关键属性。使用事件采购时,我们只能通过Id获取域对象。
BTW:在需求,如果输入的用户名已被使用,该网站应显示错误消息“对不起,该用户名XXX不可用”的访问者。显示一条消息,例如说,“我们正在创建您的帐户,请等待,我们会在稍后通过电子邮件将注册结果发送给您”,这是不能接受的。
任何想法?非常感谢!
[更新]
更复杂的例子:
要求:
下订单时,系统应检查客户的订货历史,如果他是一个有价值的客户(如果客户在过去一年每月至少订购10份订单,他很有价值),我们将订单打九折。
实现:
我们创造PlaceOrderCommand,并在命令中,我们需要查询订货历史,看看如果客户是有价值的。但我们怎么做到这一点?我们不应该在命令中使用ReadModel!作为Mikael said,我们可以在帐户注册示例中使用补偿命令,但是如果我们也在此排序示例中使用补偿命令,则它会太复杂,并且代码可能太难以维护。
当我发现用户名重复时,我应该在补偿命令中做些什么?发布SignalR事件以通知客户端用户名不可用? (我没有使用过SignalR,我想可能会有某种“事件?”) – 2012-02-29 09:21:32
很好的答案,谢谢!但是我对“域名服务”感到困惑,你是不是指“事件处理程序”?我认为它与DDD中的“域服务”不一样吗? – 2012-02-29 13:00:14
我认为我们称之为DDD中的应用服务,但我可能弄错了,而域服务在DDDD/CQRS社区中是一个争论的话题。除了你可能不需要状态机或状态机之外,它们与他们所说的Saga类似,你只需要一些能够反应和反馈事件,执行数据查找和调度命令的东西,我称之为域服务。订阅事件和发送命令,这在聚合根节点之间进行通信时非常有用 – 2012-02-29 14:48:35