CQRS - 在 C# 中使用 Mediatr 创建 BaseCommandHandler,ASP.net 核心

CQRS - Creating BaseCommandHandler using Mediatr in C#, ASP.net Core

所以我了解了 Jimmy Bogard 创建的 Mediatr,我真的很惊讶我们如何使用 Mediatr 实现 CQRS 模式。

我开始在我的应用程序中实现它,然后我意识到我的应用程序中可能有数百个 Entities,并且对于每个实体我不确定是否创建单独的命令和查询,那会与 DRY 刚好相反。所以我开始编写基本命令和处理程序。

public abstract class CreateBaseCommand : IRequest
{    
}

public abstract class DeleteBaseCommand : IRequest
{
}  //... and so on.

以及各自的处理程序。

public abstract class CreateBaseHandler : IRequestHandler<CreateBaseCommand>
{
}

public abstract class DeleteBaseCommandHandler : IRequestHandler<DeleteBaseCommand>
{
}//... and so on.

但我意识到,我的域实体仍然需要单独的命令,并且它们必须分别派生自它们的基本命令。

然后我想如果我可以将所有命令放在一个并且只有一个基本处理程序。

    public abstract class BaseCommand : IRequest
    { 
       int CommandType
    }

    public abstract class BaseCommandHandler : IRequestHandler<BaseCommand>
    {
       public Task<Unit> Handle(BaseCommand request, CancellationToken cancellationToken)
       {
        if (CommandType == 0)
        {
            // Create entity
        }
        if (CommandType == 1)
        {
            // Update entity
        }//.. and so on
      }
    }

我想知道是否有更有效的方法来做到这一点,我不太相信使用 CommandType 的想法并且有一个 handle 方法来执行所有 CRUD 操作。

这是一个好方法还是我应该为每个域实体设置单独的命令集?

从技术上讲,您应该为每个创建一个单独的命令。添加一个碱基不会给你带来太多好处,而且会使结构复杂化,所以我会去掉它。

真正的问题是您是从数据模型而非领域模型的角度考虑这个问题的。当您应该为每个商业创意创建一个命令时,您正在为每个 table 行创建一个命令。

例如,假设您正在编写一个零售系统并为注册用户创建一个新订单,并且该订单有 5 个订单项。从数据模型的角度来看,您需要为订单发送 1 个创建命令,为订单项发送 5 个创建命令。应该发生的是发送一个命令 AddNewOrderCommand 并让用户 class 处理它。 User class 方法然后创建新的订单数据库行和所有订单项。您如何添加订单(要创建哪些行等)现在封装在它所属的方法中,而不是您的命令架构中。

您是否在为您的应用程序使用域驱动设计?如果不是,您应该考虑它,因为它非常适合复杂系统,如果您有数百个实体,那么这很可能是一个复杂系统。用 DDD 的说法,上面的用户称为聚合根,订单和行项目只是实体。您没有实体的创建命令,只有聚合根。 (请注意,class 有时可以同时是聚合根和另一个聚合根中的普通实体。为什么会发生这种情况以及如何处理它超出了这个问题的范围)

查看您的模型并找到没有意义的东西,除非它们属于其他东西。例如上例中的行项目。在我的数据库中有一个与订单无关的行项目是没有意义的。因此,所有行项目都应按订单创建。拥有一个没有关联用户的订单也毫无意义。因此,用户应该创建订单。然而,用户似乎是金字塔的顶端,因此它是聚合根,确实需要创建命令。

如果你分析你的域,你会发现你几乎不需要那么多创建命令,所以问题就消失了。