Cqrs “处理”;有效地;CQR中的重复命令

Cqrs “处理”;有效地;CQR中的重复命令,cqrs,Cqrs,我们有一些类似的代码: public class Vehicle : Entity<int>, IAggregateRoot { public async Task UpdatePassengers(UpdatePassengersCommand command, IValidatorProvider commandValidator, CancellationToken cancellationToken) { await comm

我们有一些类似的代码:

public class Vehicle : Entity<int>, IAggregateRoot
{
    public async Task UpdatePassengers(UpdatePassengersCommand command, IValidatorProvider commandValidator, 
        CancellationToken cancellationToken)
    {
        await commandValidator.ValidateAndThrowAsync(command, cancellationToken);
    
        var domainEvent = new PassengersUpdatedEvent
        {
            VehicleId = Id,
            PrecintId = PrecintId,
            Passengers = new List<Passenger>(command.Passengers),
        };
    
        ApplyAndRaise(domainEvent);
    }
}
公共类车辆:实体,IAggregateRoot
{
公共异步任务UpdatePassenger(UpdatePassengersCommand命令、IValidatorProvider命令验证程序、,
取消令牌(取消令牌)
{
等待commandValidator.ValidateAndThrowAsync(命令,cancellationToken);
var domainEvent=new PassengersUpdatedEvent
{
VehicleId=Id,
PrecintId=PrecintId,
乘客=新名单(命令乘客),
};
ApplyAndRaise(domainEvent);
}
}
如果命令格式不正确,将验证并拒绝这些命令。否则将创建并应用事件。问题是前端(我们无法控制)存在bug,导致它发送的事件实际上是重复的。换言之,它可能会发送乘客Alice和Bob,然后不久它可能会发送Bob和Alice。就业务而言,乘客仍然是相同的,因此无需应用更新

应如何以及在何处执行此检查?在UpdatePassenger方法本身中?如果在这里,是否应该将其包装在另一个传递到方法中的验证器中(可能是针对聚合验证命令的验证器)?或者车辆实体本身是否应包含此类逻辑


或者有没有我没有想到的更好的方法来实现这一点?

通常的模式是,域实体将包含状态,它充当了以前发生过的事情的一种记忆;然后在已经发生的情况下处理命令。换句话说,想想“状态机”

ApplyAndRaise
这样的方法通常会做的一件事就是修改实体的状态。因此,诀窍是让代码以允许您检测重复工作的方式更新实体,以便您可以跳过它

您在这里的示例表明,某个地方有一个乘客列表,因此代码可能如下所示:

public async Task UpdatePassengers(UpdatePassengersCommand command, IValidatorProvider commandValidator, 
        CancellationToken cancellationToken)
{
    await commandValidator.ValidateAndThrowAsync(command, cancellationToken);

    if (! this.passengerList.equals(command.Passengers)) {
    
        var domainEvent = new PassengersUpdatedEvent
        {
            VehicleId = Id,
            PrecintId = PrecintId,
            Passengers = new List<Passenger>(command.Passengers),
        };
    
        ApplyAndRaise(domainEvent);
    }
}
public async Task updateAssengers(updateAssengersCommand命令、ivalidtorProvider命令验证器、,
取消令牌(取消令牌)
{
等待commandValidator.ValidateAndThrowAsync(命令,cancellationToken);
如果(!this.passengerList.equals(command.Passengers)){
var domainEvent=new PassengersUpdatedEvent
{
VehicleId=Id,
PrecintId=PrecintId,
乘客=新名单(命令乘客),
};
ApplyAndRaise(domainEvent);
}
}
2010年,Marc de Graauw建议,出于这个原因:您的域逻辑应该足够智能,能够检测到冗余的更改