【发布时间】:2018-11-18 11:15:55
【问题描述】:
我正在使用 CQRS。我读到的所有地方都告诉我将验证逻辑放在命令对象中。例如,看这个链接:https://lostechies.com/jimmybogard/2016/04/29/validation-inside-or-outside-entities/
请看下面的命令(取自链接):
public class ChangeNameCommand {
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
以及下面的业务对象(也取自链接 - 请注意,我已将传递给 Customer 构造函数的参数从类更改为接口):
public class Customer
{
public string FirstName { get; private set; }
public string LastName { get; private set; }
public void ChangeName(IChangeNameCommand command) {
FirstName = command.FirstName;
LastName = command.LastName;
}
}
在我的例子中,命令存储在一个类库中,业务对象存储在其他类库中(因为命令由多个微服务类型项目共享)。如果我遵循指导(并将验证放在命令中),那么我相信没有什么可以阻止开发人员这样做:
public class ChangeNameCommandWithoutValidation : IChangeNameCommand {
public string FirstName { get; set; }
public string LastName { get; set; }
}
然后将命令(没有验证)传递给域对象。在这种情况下,我相信域对象无法控制传递给它的内容?
因此,我是否应该违反我能找到的所有指导并在域对象中进行验证?我相信我应该这样做,因为这些命令位于与域对象不同的类库中。我是否理解正确?
我相信这个问题在将事件传递给客户域对象时也很重要(使用事件溯源时)。
【问题讨论】:
-
我认为您可能最好让命令处理程序处理特定命令。然后你可以在那里验证命令,然后调用聚合或实体来执行域逻辑。通过这种方式,您可以拥有一种漂亮而干净的用例方式。我不喜欢将命令直接传递到聚合中,因为它们应该对自己以及它们应该保护的各自实体进行操作等等。但总而言之,这里没有灵丹妙药,请按照您的团队/合作伙伴的决定并可以工作/处理。
-
@kayess,这是否意味着域模型类可能无效(如果开发人员忘记或不小心从命令中删除了验证)?
-
我不这么认为,您应该在您的 SUT 周围进行单元/集成/其他测试,这将负责确保此类事故不会发生。但正如我最喜欢的一句话所说:“没有针对人类波什的保护措施”。你也可以做验证 AOP 风格,比如有一个装饰器......另一种思考方式,你可以进行代码审查等,但这已经失控,因为我们有点太宽泛了。
-
我不是 CQRS 方面的专家,但我觉得您使用命令界面很奇怪。一个命令接口有多种实现是否有意义?我认为您的
ChangeNameCommandWithoutValidation示例表明事实并非如此。一个较少的 "evil" 示例是带有中间名的IChangeNameCommand。您的Customer实体会接受这样的命令,但实际上并不能真正处理它。 -
关于您上次的编辑,您没有将事件传递给域对象。您将(如您所做的)命令或其他参数传递给您的域对象,告诉他们做某事。您的域对象或命令处理程序引发由事件处理程序处理的事件...区别是命令 = 现在,事件 = 发生了一些事情,因为与域逻辑有一些交互。
标签: c# domain-driven-design microservices