使用 CQRS 将多个内容保留在一个命令处理程序中

Viv*_*ndi 2 design-patterns domain-driven-design cqrs

我正在尝试将 CQRS+ES 应用于我的宠物项目。但我不确定如何处理复杂的命令。

假设我有一个网页,您可以在其中创建新的User. 因此,在该页面上,您只需输入名字、姓氏、用户名和密码即可。但是,您还必须Role向该用户添加一个或多个s。当点击“保存”按钮时,将触发以下命令CreateUserWithRolesCommand

以下是命令处理程序中的有效方法吗?

public class CreateUserWithRolesCommandHandler : ICommandHandler<CreateUserWithRolesCommand>
{
    private readonly AppDbContext _context;

    public UserCommandHandler(AppDbContext context)
    {
        _context = context;
    }

    public void Handle(CreateUserCommand command)
    {
        // todo: begin db transaction 

        var user = new User();
        user.Username = command.Username;
        user.Password = command.Password;
        user.Firstname = command.Firstname;
        user.Lastname = command.Lastname;
        _context.User.Add(user);
        _context.Save();

        // After save, get user id
        van userId = user.Id;

        van userRoles = new UserRoles;

        // Ommiting foreach loop and just taking the 
        // first role to keep the example simpler
        userRole.RoleId = command.Roles.First().RoleId;
        userRole.UserId = userId;
        _context.UserRoles.Add(userRole);
        _context.Save();

        // end db transaction and commit if all successful
    }
}
Run Code Online (Sandbox Code Playgroud)

Con*_*enu 6

我首先看到的是贫血领域模型。你只有二传手,这是不行的。将所有 setter 替换为命令方法。在这种情况下,您应该只有一个User.create(usename, password, firstName, lastName)返回 void 的方法。

其次,有两个聚合,因此您需要有两个事务。在您的代码中只有一笔交易。请记住,聚合是最大的事务边界

但是,您会考虑到在第二个事务(角色被添加到用户)之前可能(并且将会)发生一些不好的事情。例如,用户刚刚添加到存储库后,服务器就重新启动或崩溃。重新启动后,它将没有足够的信息来继续添加用户角色的过程。

一个解决方案是将其建模为Saga/Process 管理器。您将拥有一个使用所有所需信息创建的 CreateUserWithRoles 实体。在这种情况下,CreateUserCommand 的内容就足够了。然后,您需要添加一个progress状态变量,即一个枚举(Started、UserCreated 和 RoleAdded),它将 记住上次执行的状态和/或使 User.create 和 UserRoles.add 幂等。创建 CreateUserWithRoles 实体后run即可。该run方法通过查看跳过已执行的步骤progress并执行剩余的步骤。这样,如果发生不好的事情(相信我,它会发生),Saga 就可以恢复。

您还需要一种方法来检测所有处于停止状态的 Sagas 并恢复它们(通过执行它们的run方法)。

PS:我使用术语“事务”来表达这样一个事实:操作必须以原子模式(全部或全部)完成,但可扩展的事件存储实现根本不应该使用数据库事务。