ハンドラインと純粋CQRSを達成

CQRS自体はシンプルなのでCQRSについて、実現には多くの違いが、ありますが、それはパンドラの箱の鍵のようなものです、それを読み、分離、トレーサビリティイベント、メッセージングを書き、その結果整合性のためのフレームワークを導入しました。 、あまりにも多くの混乱を運ぶCQRSになります。この記事では、ES、メッセージングの概念に依存しない、達成シンプルCQRSを提供することを目指し、自分自身のみに関心CQRS。

CQRSがそれをある自然とは何ですか?私の理解では、それが読み取りを分離し、読み、異なるデータモデルを使用して書き込み、読み出しと書き込みの職務に基づいて、適切なオブジェクトを作成するために、書くということである。他の概念に加えて、CQRSの拡張です。

次の擬似コードは、CQRSの性質を示しています。

CQRSを使用する前に:

顧客サービス

void MakeCustomerPreferred(CustomerId) 
Customer GetCustomer(CustomerId) 
CustomerSet GetCustomersWithName(Name) 
CustomerSet GetPreferredCustomers() 
void ChangeCustomerLocale(CustomerId, NewLocale) 
void CreateCustomer(Customer) 
void EditCustomerDetails(CustomerDetails)

CQRSを使用した後:

CustomerWriteService

void MakeCustomerPreferred(CustomerId) 
void ChangeCustomerLocale(CustomerId, NewLocale) 
void CreateCustomer(Customer) 
void EditCustomerDetails(CustomerDetails)

CustomerReadService

Customer GetCustomer(CustomerId) 
CustomerSet GetCustomersWithName(Name) 
CustomerSet GetPreferredCustomers()

質問

クエリ(クエリ):結果を返すが、オブジェクト、システム上の副作用なしの状態を変更しません。

比較的単純なため、クエリ、我々は最初の読み取り専用のストレージを定義します。

public interface IReadonlyBookRepository
{
    IList<BookItemDto> GetBooks();

    BookDto GetById(string id);
}

そして、コントローラでそれを使用します。

public IActionResult Index()
{
    var books = readonlyBookRepository.GetBooks();

    return View(books);
}

コマンド

コマンド(コマンド):何の結果は(ボイド)が返されませんが、オブジェクトの状態を変更します。

コマンドは、ビジネス・データが含まれ、ユーザの意図を表しています。

最初の任意のメソッドおよびプロパティが含まれていないのICommandインターフェースを定義し、それが唯一のマーカーとして使用されます。

public interface ICommand
{
    
}

対応CommandHandler、ハンドラにコマンドが特定の操作を定義します。

public interface ICommandHandler<TCommand>
    where TCommand : ICommand
{
    void Execute(TCommand command);
}

パッケージハンドラを配置するために、我々はまた、ICommandHandlerFactoryを設定する必要があります。

public interface ICommandHandlerFactory
{
    ICommandHandler<T> GetHandler<T>() where T : ICommand;
}

ICommandHandlerFactory実装:

public class CommandHandlerFactory : ICommandHandlerFactory
{
    private readonly IServiceProvider serviceProvider;

    public CommandHandlerFactory(IServiceProvider serviceProvider) 
    {
        this.serviceProvider = serviceProvider;
    }

    public ICommandHandler<T> GetHandler<T>() where T : ICommand
    {
        var types = GetHandlerTypes<T>();
        if (!types.Any())
        {
            return null;
        }
        
        //实例化Handler
        var handler = this.serviceProvider.GetService(types.FirstOrDefault()) as ICommandHandler<T>;
        return handler;
    }

    //这段代码来自Diary.CQRS项目,用于查找Command对应的CommandHandler
    private IEnumerable<Type> GetHandlerTypes<T>() where T : ICommand
    {
        var handlers = typeof(ICommandHandler<>).Assembly.GetExportedTypes()
            .Where(x => x.GetInterfaces()
                .Any(a => a.IsGenericType && a.GetGenericTypeDefinition() == typeof(ICommandHandler<>)))
                .Where(h => h.GetInterfaces()
                    .Any(ii => ii.GetGenericArguments()
                        .Any(aa => aa == typeof(T)))).ToList();


        return handlers;
    }

その後、我々はコマンドを送信し、Sendメソッド経由でコマンドを実行するために、ICommandBusをICommandBusを定義します。これは次のように定義されます。

public interface ICommandBus
{
    void Send<T>(T command) where T : ICommand;
}

ICommandBusの実装:

public class CommandBus : ICommandBus
{
    private readonly ICommandHandlerFactory handlerFactory;

    public CommandBus(ICommandHandlerFactory handlerFactory)
    {
        this.handlerFactory = handlerFactory;
    }

    public void Send<T>(T command) where T : ICommand
    {
        var handler = handlerFactory.GetHandler<T>();
        if (handler == null)
        {
            throw new Exception("未找到对应的处理程序");
        }

        handler.Execute(command);
    }
}

のは、新しいコマンドCreateBookCommandを設定してみましょう:

public class CreateBookCommand : ICommand
{
    public CreateBookCommand(CreateBookDto dto)
    {
        this.Dto = dto;
    }

    public CreateBookDto Dto { get; set; }
}

私はどこに直接DTOが合理的であるオブジェクトを初期化するかわからないので、私は達成されるであろう

CreateBookCommandハンドラは次のように対応します:

public class CreateBookCommandHandler : ICommandHandler<CreateBookCommand>
{
    private readonly IWritableBookRepository bookWritableRepository;

    public CreateBookCommandHandler(IWritableBookRepository bookWritableRepository)
    {
        this.bookWritableRepository = bookWritableRepository;
    }

    public void Execute(CreateBookCommand command)
    {
        bookWritableRepository.CreateBook(command.Dto);
    }
}

我々はコントローラを使用する場合は、次のように、コードは次のとおりです。

[HttpPost]
public IActionResult Create(CreateBookDto dto)
{
    dto.Id = Guid.NewGuid().ToString("N");
    var command = new CreateBookCommand(dto);
    commandBus.Send(command);

    return Redirect("~/book");
}

単に操作のフロントエンドにCommandBusにコマンドを送信することによって、知らずUIレイヤコマンドの実行も非常に簡単です。

githubの上でこの例の完全なコード、および興味の友人移動してください>> https://github.com/qifei2012/cqrs_sample

エラーや不適切な場所がコードである場合は、コメント欄に明記してくださいお願いしますサポートしています。

参考資料

おすすめ

転載: www.cnblogs.com/youring2/p/10991338.html