命令中的 CQRS 代码重复

use*_*743 4 dry duplication repository cqrs

我在 CQRS 原则的命令端有一个关于代码重复的问题。

一直在关注以下文章:

https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91 https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92

在我看来,在从数据存储中检索实体时,这种将每个命令分离到它自己的类中的方法会产生一些代码重复。

也许有点做作,但假设例如我有一个命令,我想根据他的电子邮件地址重置用户密码,还有一个命令我想更新用户的上次登录日期。

public class ResetPasswordCommandHandler : CommandHandler<ResetPasswordCommand>
{
    public override void Execute(ResetPasswordCommand command)
    {
       **// duplication here**
        var user = from c in db.Users
            where c.EmailAddress = command.EmailAddress
            select c;

        user.EmailAddress = command.EmailAddress;
        ...
        db.Save();
   }
}

public class UpdateLastLoginCommandHandler : CommandHandler<UpdateLastLoginCommand>
{
    public override void Execute(UpdateLastLoginCommand command)
    {
       **// duplication here**
        var user = from c in db.Users
            where c.EmailAddress = command.EmailAddress
            select c;

        user.LastLogin = DateTime.Now;
        ...
        db.Save();
   }
}
Run Code Online (Sandbox Code Playgroud)

在这两个命令中,我都根据用户的电子邮件地址检索用户。现在,如果我想在查询数据库之前修剪 UI 输入,我将不得不在两个地方进行更改。

我当然可以创建一个 UserRepository,例如,有一个方法 GetUserByEmailAddress 并将该 IUserRepository 插入到我的 CommandHandlers 的构造函数中。但是,这不会最终创建一个带有 Save、GetById、GetByUsername 等的“上帝存储库”吗?

如果我创建了一个存储库,为什么要创建单独的 Query 对象?

如何保持此代码干燥?

Dav*_*ter 5

为什么不将您的命令处理程序重构为一个实现多个接口的处理程序:

public class UserCommandHandler : CommandHandlerBase, 
                                  IHandle<ResetPasswordCommand>,
                                  IHandle<UpdateLastLoginCommand>
{
    public void Execute(ResetPasswordCommand command)
    {
        var user = GetUserByEmail(command.EmailAddress);

        user.EmailAddress = command.EmailAddress;
        ...
        db.Save();
   }

    public void Execute(UpdateLastLoginCommand command)
    {
        var user = GetUserByEmail(command.EmailAddress);

        user.LastLogin = DateTime.Now;
        ...
        db.Save();
   }

   private User GetUserByEmail(string email) {
            return (from c in db.Users
                   where c.EmailAddress = command.EmailAddress
                   select c).FirstOrDefault();
   }
}
Run Code Online (Sandbox Code Playgroud)

这样,您可以在命令处理程序中重构私有帮助程序方法,您的命令处理程序可以处理类似的命令,并减少代码重复。您也不需要“上帝”存储库。

就我个人而言,我宁愿将私有GetUserByEmail帮助程序作为一个单独的查询类,我db通过构造函数将上下文注入其中,因此这GetUserByEmail是一个非常具体的类,可以让我获得User.

希望这可以帮助。