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