CQRS - Executing Commands within Commands

眉间皱痕 提交于 2020-12-01 11:12:32

问题


I recently saw some code scenarios where CommandHandlers were being injected with ICommandExecutor to call other commands. So commands within commands. This was also true for some QueryHandlers being injected with IQuery.

public class UpdateCarDetailsCommandHandler : CommandHandler<UUpdateCarDetailsCommand>
{
   private ICommandExecutor _command;

   public UpdateCarDetailsCommandHandler (ICommandExecutor command)
   {
       _command = command;
   }     

    public override void Execute(UpdateCarDetailsCommand command)
    {
        //do something with repository 
        _command.Execute(new CarColour())   
    }
}

This seems incorrect to me, as the ICommandExecutor would be the composition root in this scenario. Just wondered people thoughts on this?


回答1:


I say you are correct to be wary of using commands and queries within other commands and queries. Beware abstractions that do too much.

The S in CQRS stands for Segregation. This clearly implies that Commands should remain separate from other Commands and Queries should remain separate from other Queries. But can queries be used by commands? As always, it depends.

Udi Dahan's article from 2009 suggests not:

Since your queries are now being performed off of a separate data store than your master database, and there is no assumption that the data that’s being served is 100% up to date, you can easily add more instances of these stores without worrying that they don’t contain the exact same data.

Dino Esposito recommends using separate projects:

Applying CQRS means you’ll use two distinct middle tiers. One tier takes care of commands that alter the system state. The other retrieves the data. You create a couple of class library projects—query stack and command stack—and reference both from the main Web server project.

My personal view is that you should think of these standard Command and Query handlers as holistic abstractions. A holistic abstraction is an abstraction that is concerned with the whole transaction; it cannot be a dependency within something larger than itself within the confines of a single transaction.

What is needed instead are similar pairs of abstractions that are injectable strategies and that can be decorated with cross-cutting concerns.

E.g.

public interface IDataCommandHandler<TCommand> where TCommand : IDataCommand
{
    void Handle(TCommand command);
}

public interface IDataQueryHandler<TQuery, TResult> where TQuery : IDataQuery<TResult>
{
    TResult Handle(TQuery query);
}

Or

public interface ICommandStrategyHandler<TCommand> where TCommand : ICommand
{
    void Handle(TCommand command);
} 

public interface IQueryStrategyHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
    TResult Handle(TQuery query);
}


来源:https://stackoverflow.com/questions/31203506/cqrs-executing-commands-within-commands

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!