Search code examples
c#.netdesign-patternscqrsmediatr

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


So I learned about Mediatr created by Jimmy Bogard and it really amazed me how we achieve CQRS pattern using Mediatr.

I started to implement it in my application, and then I realized that I might have hundreds of Entities in my application, and for each Entity I am not sure about creating separate commands and queries, that would be just opposite of DRY. So I started writing base commands and handlers.

public abstract class CreateBaseCommand : IRequest
{    
}

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

And respective handlers.

public abstract class CreateBaseHandler : IRequestHandler<CreateBaseCommand>
{
}

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

But I realised, I would still need separate commands for my domain entities, and they will have to derive from their Base commands respectively.

Then I though if I can just put all commands in one and have just one base handler.

    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
      }
    }

I was wondering if there is more efficient way to do this, I am not very convinced with idea of using CommandType and have one handle method to perform all CRUD operations.

Is this a good approach or should I have separate set of commands for each domain entity?


Solution

  • Technically you should have a separate command for each creation. Adding a base doesn’t get you much, and complicates the structure so I would get rid of that.

    The real problem is that you’re thinking of this from the point of view of your data model, not your domain model. You’re creating a command per table row when you should be creating a command per business idea.

    For example, say you’re writing a retail system and creating a new order for a registered user, and that order has 5 line items. Looking at this from the data model point of view, you need to send 1 create command for the order and 5 create commands for the line items. What should happen is to send one command AddNewOrderCommand and have the User class handle it. The User class method then creates the new order database row and all line items. How you add the order (what rows to create, etc) is now encapsulated in the method where it belongs instead of your command architecture.

    Are you using Domain Driven Design for your app? If not, you should consider it because its very good with complex systems, and if you have hundreds of entities chances are good this qualifies as a complex system. In DDD parlance, the User above is called and Aggregate Root and the Order and Line Item are just entities. You don’t have Create commands for entities, just for the Aggregate Roots. (Note that a class can sometimes be both an aggregate root and a normal entity in another aggregate root. Why this happens and how to handle it is out of scope for this question)

    Look through your model and find things that don’t make sense unless they are owned by something else. For example the line item from the example above. Having a line item in my database that’s not related to an order makes no sense. Therefore, all line items should be created by orders. Having an order with no user associated with it also makes no sense. Therefore the user should create the order. A user, however, seems to be the top of the pyramid, so it is the aggregate root and does need a Create command.

    If you analyze your domain, you’ll find you don’t need nearly so many Create commands, and so the problem disappears.