Padrão de Segregação das Responsabilidade de Comando e de Consulta (CQRS)Command and Query Responsibility Segregation (CQRS) pattern

Segregue operações de leitura de dados a partir de operações que atualizam dados através de interfaces separadas.Segregate operations that read data from operations that update data by using separate interfaces. Desta forma, poderá maximizar o desempenho, a escalabilidade e a segurança.This can maximize performance, scalability, and security. Suporta a evolução do sistema ao longo do tempo por meio de uma maior flexibilidade e impede que os comandos de atualização criem conflitos de intercalação ao nível do domínio.Supports the evolution of the system over time through higher flexibility, and prevents update commands from causing merge conflicts at the domain level.

Contexto e problemaContext and problem

Nos sistemas de gestão de dados tradicionais, os comandos (atualizações dos dados) e as consultas (pedidos de dados) são executados no mesmo conjunto de entidades num repositório de dados individual.In traditional data management systems, both commands (updates to the data) and queries (requests for data) are executed against the same set of entities in a single data repository. Estas entidades podem ser um subconjunto das linhas numa ou mais tabelas numa base de dados relacional, tal como o SQL Server.These entities can be a subset of the rows in one or more tables in a relational database such as SQL Server.

Normalmente, nestes sistemas, todas as operações de criação, leitura, atualização e eliminação (CRUD) são aplicadas à mesma representação da entidade.Typically in these systems, all create, read, update, and delete (CRUD) operations are applied to the same representation of the entity. Por exemplo, um objeto de transferência de dados (DTO) a representar um cliente é obtido do arquivo de dados pela camada de acesso aos dados (DAL) e apresentado no ecrã.For example, a data transfer object (DTO) representing a customer is retrieved from the data store by the data access layer (DAL) and displayed on the screen. Um utilizador atualiza alguns campos do DTO (por exemplo, através do enlace de dados) e, em seguida, o DTO é guardado no arquivo de dados pela DAL.A user updates some fields of the DTO (perhaps through data binding) and the DTO is then saved back in the data store by the DAL. O mesmo DTO é utilizado para as operações de leitura e escrita.The same DTO is used for both the read and write operations. A figura mostra uma arquitetura CRUD tradicional.The figure illustrates a traditional CRUD architecture.

Uma arquitetura CRUD tradicional

As estruturas CRUD funcionam bem apenas quando a lógica de negócio limitada é aplicada às operações de dados.Traditional CRUD designs work well when only limited business logic is applied to the data operations. Os mecanismos de estrutura fornecidos pelas ferramentas de desenvolvimento podem criar um código de acesso de dados muito rapidamente, o qual pode ser posteriormente personalizado, conforme necessário.Scaffold mechanisms provided by development tools can create data access code very quickly, which can then be customized as required.

No entanto, a abordagem CRUD tradicional tem algumas desvantagens:However, the traditional CRUD approach has some disadvantages:

  • Muitas vezes, significa que há um erro de correspondência entre as representações de leitura e escrita dos dados, tal como colunas ou propriedades adicionais que têm de ser atualizadas corretamente, apesar de não serem necessárias como parte de uma operação.It often means that there's a mismatch between the read and write representations of the data, such as additional columns or properties that must be updated correctly even though they aren't required as part of an operation.

  • Coloca em riscos a contenção de dados quando os registos estão bloqueados no arquivo de dados num domínio de colaboração, onde vários atores funcionam em paralelo no mesmo conjunto de dados.It risks data contention when records are locked in the data store in a collaborative domain, where multiple actors operate in parallel on the same set of data. Ou podem ocorrer conflitos de atualizações provocados por atualizações simultâneas quando é utilizado o bloqueio otimista.Or update conflicts caused by concurrent updates when optimistic locking is used. Estes riscos aumentam à medida que a complexidade e o débito do sistema crescem.These risks increase as the complexity and throughput of the system grows. Além disso, a abordagem tradicional pode ter um efeito negativo no desempenho devido à carga no arquivo de dados e na camada de acesso aos dados e a complexidade das consultas necessária para obter informações.In addition, the traditional approach can have a negative effect on performance due to load on the data store and data access layer, and the complexity of queries required to retrieve information.

  • Pode tornar a gestão da segurança e das permissões mais complexa, uma vez que cada entidade está sujeita a operações de leitura e escrita, o que pode expor dados no contexto errado.It can make managing security and permissions more complex because each entity is subject to both read and write operations, which might expose data in the wrong context.

SoluçãoSolution

A Segregação das Responsabilidade de Comando e de Consulta (CQRS) é um padrão que segrega as operações de leitura de dados (consultas) das operações que atualizam os dados (comandos) através da utilização de interfaces separadas.Command and Query Responsibility Segregation (CQRS) is a pattern that segregates the operations that read data (queries) from the operations that update data (commands) by using separate interfaces. Tal significa que os modelos de dados utilizados para as consultas e as atualizações são diferentes.This means that the data models used for querying and updates are different. Os modelos podem ser isolados, conforme mostrado na figura seguinte, embora não seja um requisito absoluto.The models can then be isolated, as shown in the following figure, although that's not an absolute requirement.

Uma arquitetura CQRS básica

Comparativamente ao modelo de dados único utilizado nos sistemas baseados no CRUD, a utilização de modelos de consulta e atualização separados para os dados em sistemas baseados no CQRS simplifica a estrutura e a implementação.Compared to the single data model used in CRUD-based systems, the use of separate query and update models for the data in CQRS-based systems simplifies design and implementation. No entanto, a desvantagem é que, ao contrário das estruturas CRUD, o código CQRS não pode ser gerado automaticamente com mecanismos de estruturas.However, one disadvantage is that unlike CRUD designs, CQRS code can't automatically be generated using scaffold mechanisms.

O modelo de consulta para a leitura de dados e o modelo de atualização para a escrita de dados podem aceder à mesma loja física, por exemplo, ao utilizar vistas SQL ou ao gerar projeções no momento.The query model for reading data and the update model for writing data can access the same physical store, perhaps by using SQL views or by generating projections on the fly. No entanto, é comum separar os dados em diferentes arquivos físicos para maximizar o desempenho, a escalabilidade e a segurança, conforme mostrado na figura seguinte.However, it's common to separate the data into different physical stores to maximize performance, scalability, and security, as shown in the next figure.

Uma arquitetura CQRS com arquivos de escrita e leitura separados

O arquivo de leitura pode ser uma réplica só de leitura do arquivo de escrita ou os arquivos de leitura e escrita podem ter uma estrutura completamente diferente.The read store can be a read-only replica of the write store, or the read and write stores can have a different structure altogether. A utilização de várias réplicas só de leitura do arquivo de leitura pode aumentar significativamente o desempenho da consulta e a capacidade de resposta da IU da aplicação, especialmente em cenários distribuídos onde as réplicas só de leitura estão localizadas próximas das instâncias da aplicação.Using multiple read-only replicas of the read store can greatly increase query performance and application UI responsiveness, especially in distributed scenarios where read-only replicas are located close to the application instances. Alguns sistemas de base de dados (SQL Server) fornecem funcionalidades adicionais, tal como réplicas de ativação pós-falha para maximizar a disponibilidade.Some database systems (SQL Server) provide additional features such as failover replicas to maximize availability.

A separação dos arquivos de leitura e escrita também permitem que cada um seja dimensionado adequadamente para corresponder à carga.Separation of the read and write stores also allows each to be scaled appropriately to match the load. Por exemplo, os arquivos de leitura encontram normalmente uma carga muito superior à dos arquivos de escrita.For example, read stores typically encounter a much higher load than write stores.

Quando o modelo de consulta/leitura contém dados desnormalizados (veja Padrão de Vista Materializada), o desempenho é maximizado durante a leitura de dados de cada uma das vistas numa aplicação ou ao consultar os dados no sistema.When the query/read model contains denormalized data (see Materialized View pattern), performance is maximized when reading data for each of the views in an application or when querying the data in the system.

Problemas e consideraçõesIssues and considerations

Na altura de decidir como implementar este padrão, considere os seguintes pontos:Consider the following points when deciding how to implement this pattern:

  • A divisão dos arquivos de dados em arquivos físicos separados para operações de leitura e escrita pode aumentar o desempenho e a segurança de um sistema, mas pode adicionar complexidade em termos de resiliência e consistência eventual.Dividing the data store into separate physical stores for read and write operations can increase the performance and security of a system, but it can add complexity in terms of resiliency and eventual consistency. O arquivo do modelo de leitura tem de ser atualizado para refletir as alterações no arquivo do modelo de escrita, podendo ser difícil detetar quando é que um utilizador emitiu um pedido com base nos dados de leitura obsoletos, o que significa que não pode concluir a operação.The read model store must be updated to reflect changes to the write model store, and it can be difficult to detect when a user has issued a request based on stale read data, which means that the operation can't be completed.

    Para obter uma descrição de consistência eventual, veja o Data Consistency Primer (Manual Básico sobre a Consistência dos Dados).For a description of eventual consistency see the Data Consistency Primer.

  • Considere aplicar o CQRS em secções limitadas do sistema onde será mais valioso.Consider applying CQRS to limited sections of your system where it will be most valuable.

  • Uma abordagem típica para implementar a consistência eventual consiste em utilizar a origem do evento em conjunto com o CQRS, para que o modelo de escrita seja um fluxo de eventos só de acréscimo condicionado pela execução de comandos.A typical approach to deploying eventual consistency is to use event sourcing in conjunction with CQRS so that the write model is an append-only stream of events driven by execution of commands. Estes eventos são utilizados para atualizar as vistas materializadas que atuam como o modelo de leitura.These events are used to update materialized views that act as the read model. Para obter mais informações, veja Origem do Evento e CQRS.For more information see Event Sourcing and CQRS.

Quando utilizar este padrãoWhen to use this pattern

Utilize este padrão nas seguintes situações:Use this pattern in the following situations:

  • Domínios de colaboração onde são realizadas várias operações em paralelo nos mesmos dados.Collaborative domains where multiple operations are performed in parallel on the same data. O CQRS permite-lhe definir comandos com granularidade suficiente para minimizar os conflitos de intercalação ao nível do domínio (eventuais conflitos que possam surgir podem ser intercalados pelo comando), mesmo durante a atualização daquilo que parece ser o mesmo tipo de dados.CQRS allows you to define commands with enough granularity to minimize merge conflicts at the domain level (any conflicts that do arise can be merged by the command), even when updating what appears to be the same type of data.

  • Interfaces de utilizador baseadas em tarefas nas quais os utilizadores são orientados através de um processo complexo como uma série de passos ou com modelos de domínio complexos.Task-based user interfaces where users are guided through a complex process as a series of steps or with complex domain models. Além disso, é útil para as equipas já familiarizadas com as técnicas de conceção condicionada por domínio (DDD).Also, useful for teams already familiar with domain-driven design (DDD) techniques. O modelo de escrita tem uma pilha de processamento de comandos completa com lógica de negócio, validação de entrada e validação de negócios para assegurar que tudo está sempre consistente para cada um dos agregados (cada cluster de objetos associados é tratado como uma unidade para as alterações de dados) no modelo de escrita.The write model has a full command-processing stack with business logic, input validation, and business validation to ensure that everything is always consistent for each of the aggregates (each cluster of associated objects treated as a unit for data changes) in the write model. O modelo de leitura não tem nenhuma lógica de negócio nem pilha de validação e devolve apenas um DTO para utilização num modelo de vista.The read model has no business logic or validation stack and just returns a DTO for use in a view model. O modelo de leitura é eventualmente consistente com o modelo de escrita.The read model is eventually consistent with the write model.

  • Cenários onde o desempenho da leitura de dados tem de ser otimizado separadamente do desempenho da escrita de dados, especialmente quando a proporção de leitura/escrita é bastante elevada e quando o dimensionamento horizontal é necessário.Scenarios where performance of data reads must be fine tuned separately from performance of data writes, especially when the read/write ratio is very high, and when horizontal scaling is required. Por exemplo, em muitos sistemas, o número de operações de leitura é muitas vezes superior ao número de operações de escrita.For example, in many systems the number of read operations is many times greater than the number of write operations. Para suportar isto, considere aumentar horizontalmente o modelo de leitura e executar o modelo de escrita apenas numa ou em algumas instâncias.To accommodate this, consider scaling out the read model, but running the write model on only one or a few instances. Um pequeno número de instâncias do modelo de escrita também ajuda a minimizar a ocorrência de conflitos de intercalação.A small number of write model instances also helps to minimize the occurrence of merge conflicts.

  • Cenários onde uma equipa de programadores pode concentrar-se no modelo de domínio complexo que faz parte do modelo de escrita e outra equipa pode concentrar-se no modelo de leitura e nas interfaces de utilizador.Scenarios where one team of developers can focus on the complex domain model that is part of the write model, and another team can focus on the read model and the user interfaces.

  • Cenários onde se espera que o sistema evolua ao longo do tempo e possa conter várias versões do modelo ou onde as regras de negócio são alteradas regularmente.Scenarios where the system is expected to evolve over time and might contain multiple versions of the model, or where business rules change regularly.

  • Integração com outros sistemas, especialmente em conjunto com a origem do evento, onde a falha temporária de um subsistema não deve afetar a disponibilidade dos outros.Integration with other systems, especially in combination with event sourcing, where the temporal failure of one subsystem shouldn't affect the availability of the others.

Este padrão não é recomendando nas seguintes situações:This pattern isn't recommended in the following situations:

  • Quando o domínio ou as regras de negócio são simples.Where the domain or the business rules are simple.

  • Quando uma interface de utilizador de estilo CRUD simples e as operações de acesso de dados relacionadas são suficientes.Where a simple CRUD-style user interface and the related data access operations are sufficient.

  • Para a implementação em todo o sistema.For implementation across the whole system. Existem componentes específicos de um cenário de gestão de dados geral em que o CQRS pode ser útil, mas este pode adicionar uma complexidade desnecessária e considerável quando não é necessário.There are specific components of an overall data management scenario where CQRS can be useful, but it can add considerable and unnecessary complexity when it isn't required.

Origem do Evento e CQRSEvent Sourcing and CQRS

O padrão CQRS é frequentemente utilizado juntamente com o padrão de Origem do Evento.The CQRS pattern is often used along with the Event Sourcing pattern. Os sistemas baseados no CQRS utilizam modelos de leitura e escrita separados, cada um personalizado para tarefas relevantes e, muitas vezes, localizados em arquivos fisicamente separados.CQRS-based systems use separate read and write data models, each tailored to relevant tasks and often located in physically separate stores. Quando utilizado com o padrão de origem do evento, o arquivo de eventos é o modelo de escrita e é a origem de informações oficial.When used with the Event Sourcing pattern, the store of events is the write model, and is the official source of information. O modelo de leitura de um sistema baseado no CQRS fornece vistas materializadas dos dados, normalmente, como vistas altamente desnormalizadas.The read model of a CQRS-based system provides materialized views of the data, typically as highly denormalized views. Estas vistas são personalizadas para as interfaces e apresentam os requisitos da aplicação, o que ajuda a maximizar o desempenho da apresentação e da consulta.These views are tailored to the interfaces and display requirements of the application, which helps to maximize both display and query performance.

Com o fluxo de eventos como arquivo de escrita, em vez dos dados reais num ponto no tempo, evita conflitos de atualização numa agregação única e maximiza o desempenho e a escalabilidade.Using the stream of events as the write store, rather than the actual data at a point in time, avoids update conflicts on a single aggregate and maximizes performance and scalability. Os eventos podem ser utilizados para gerar de forma assíncrona vistas materializadas dos dados utilizados para preencher o arquivo de leitura.The events can be used to asynchronously generate materialized views of the data that are used to populate the read store.

Uma vez que o arquivo de eventos é a origem de informações oficial, é possível eliminar as vistas materializadas e repetir todos os eventos anteriores para criar uma nova representação do estado atual quando o sistema evolui ou quando o modelo de leitura tem de ser alterado.Because the event store is the official source of information, it is possible to delete the materialized views and replay all past events to create a new representation of the current state when the system evolves, or when the read model must change. As vistas materializadas estão em vigor numa cache só de leitura durável dos dados.The materialized views are in effect a durable read-only cache of the data.

Quando utilizar o CQRS combinado com o padrão de Origem do Evento, considere o seguinte:When using CQRS combined with the Event Sourcing pattern, consider the following:

  • À semelhança de qualquer sistema onde os arquivos de escrita e leitura estão separados, os sistemas com base neste padrão são apenas eventualmente consistentes.As with any system where the write and read stores are separate, systems based on this pattern are only eventually consistent. Haverá algum atraso entre a geração do evento e a atualização do arquivo de dados.There will be some delay between the event being generated and the data store being updated.

  • O padrão adiciona complexidade pois o código tem de ser criado para iniciar e processar eventos e montar ou atualizar as vistas ou os objetos adequados necessários para as consultas ou um modelo de leitura.The pattern adds complexity because code must be created to initiate and handle events, and assemble or update the appropriate views or objects required by queries or a read model. A complexidade do padrão CQRS quando utilizado com o padrão de Origem do Evento pode tornar mais difícil uma implementação bem-sucedida e precisa de uma abordagem diferente para a criação de sistemas.The complexity of the CQRS pattern when used with the Event Sourcing pattern can make a successful implementation more difficult, and requires a different approach to designing systems. No entanto, a origem do evento pode tornar mais fácil modelar o domínio e reconstruir as vistas, ou criar novas, uma vez o objetivo das alterações nos dados é preservado.However, event sourcing can make it easier to model the domain, and makes it easier to rebuild views or create new ones because the intent of the changes in the data is preserved.

  • Gerar vistas materializadas para utilizar no modelo de leitura ou nas projeções de dados ao reproduzir e processar os eventos para entidades ou coleções de entidades específicas pode exigir um tempo de processamento e uma utilização de recursos significativos.Generating materialized views for use in the read model or projections of the data by replaying and handling the events for specific entities or collections of entities can require significant processing time and resource usage. Tal é particularmente verdade se for necessário um resumo da análise dos valores durante longos períodos, porque todos os eventos associados podem ter de ser examinados.This is especially true if it requires summation or analysis of values over long periods, because all the associated events might need to be examined. Resolva este problema através da implementação de instantâneos dos dados em intervalos agendados, tal como uma contagem total do número de uma ação específica que ocorreu ou o estado atual de uma entidade.Resolve this by implementing snapshots of the data at scheduled intervals, such as a total count of the number of a specific action that have occurred, or the current state of an entity.

ExemploExample

O código seguinte mostra alguns extratos de um exemplo de uma implementação do CQRS que utiliza definições diferentes para os modelos de leitura e escrita.The following code shows some extracts from an example of a CQRS implementation that uses different definitions for the read and the write models. As interfaces do modelo não ditam quaisquer funcionalidades dos arquivos de dados subjacentes e podem evoluir e ser otimizadas de forma independente, uma vez que são interfaces separadas.The model interfaces don't dictate any features of the underlying data stores, and they can evolve and be fine-tuned independently because these interfaces are separated.

O código seguinte mostra a definição do modelo de leitura.The following code shows the read model definition.

// Query interface
namespace ReadModel
{
  public interface ProductsDao
  {
    ProductDisplay FindById(int productId);
    ICollection<ProductDisplay> FindByName(string name);
    ICollection<ProductInventory> FindOutOfStockProducts();
    ICollection<ProductDisplay> FindRelatedProducts(int productId);
  }

  public class ProductDisplay
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal UnitPrice { get; set; }
    public bool IsOutOfStock { get; set; }
    public double UserRating { get; set; }
  }

  public class ProductInventory
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public int CurrentStock { get; set; }
  }
}

O sistema permite aos utilizadores classificar os produtos.The system allows users to rate products. O código de aplicação realiza esta operação com o comando RateProduct mostrado no código seguinte.The application code does this using the RateProduct command shown in the following code.

public interface ICommand
{
  Guid Id { get; }
}

public class RateProduct : ICommand
{
  public RateProduct()
  {
    this.Id = Guid.NewGuid();
  }
  public Guid Id { get; set; }
  public int ProductId { get; set; }
  public int Rating { get; set; }
  public int UserId {get; set; }
}

O sistema utiliza a classe ProductsCommandHandler para processar os comandos enviados pela aplicação.The system uses the ProductsCommandHandler class to handle commands sent by the application. Por norma, os clientes enviam comandos para o domínio através de um sistema de mensagens, tal como uma fila.Clients typically send commands to the domain through a messaging system such as a queue. O processador de comandos aceita estes comandos e invoca métodos da interface de domínio.The command handler accepts these commands and invokes methods of the domain interface. A granularidade de cada comando é concebida para reduzir a possibilidade de pedidos em conflito.The granularity of each command is designed to reduce the chance of conflicting requests. O código seguinte mostra uma descrição da classe ProductsCommandHandler.The following code shows an outline of the ProductsCommandHandler class.

public class ProductsCommandHandler :
    ICommandHandler<AddNewProduct>,
    ICommandHandler<RateProduct>,
    ICommandHandler<AddToInventory>,
    ICommandHandler<ConfirmItemShipped>,
    ICommandHandler<UpdateStockFromInventoryRecount>
{
  private readonly IRepository<Product> repository;

  public ProductsCommandHandler (IRepository<Product> repository)
  {
    this.repository = repository;
  }

  void Handle (AddNewProduct command)
  {
    ...
  }

  void Handle (RateProduct command)
  {
    var product = repository.Find(command.ProductId);
    if (product != null)
    {
      product.RateProduct(command.UserId, command.Rating);
      repository.Save(product);
    }
  }

  void Handle (AddToInventory command)
  {
    ...
  }

  void Handle (ConfirmItemsShipped command)
  {
    ...
  }

  void Handle (UpdateStockFromInventoryRecount command)
  {
    ...
  }
}

O código seguinte mostra a interface IProductsDomain do modelo de escrita.The following code shows the IProductsDomain interface from the write model.

public interface IProductsDomain
{
  void AddNewProduct(int id, string name, string description, decimal price);
  void RateProduct(int userId, int rating);
  void AddToInventory(int productId, int quantity);
  void ConfirmItemsShipped(int productId, int quantity);
  void UpdateStockFromInventoryRecount(int productId, int updatedQuantity);
}

Repare também como a interface IProductsDomain contém métodos que têm um significado no domínio.Also notice how the IProductsDomain interface contains methods that have a meaning in the domain. Normalmente, num ambiente CRUD, estes métodos teriam nomes genéricos, como Save ou Update, e teriam um DTO como único argumento.Typically, in a CRUD environment these methods would have generic names such as Save or Update, and have a DTO as the only argument. A abordagem CQRS pode ser concebida para satisfazer as necessidades dos sistemas de gestão de inventário e negócios desta organização.The CQRS approach can be designed to meet the needs of this organization's business and inventory management systems.

Os padrões e as orientações que se seguem são úteis ao implementar este padrão:The following patterns and guidance are useful when implementing this pattern:

  • Para uma comparação do CQRS com outros estilos de arquitetura, veja Estilos de arquitetura e Estilo de arquitetura CQRS.For a comparison of CQRS with other architectural styles, see Architecture styles and CQRS architecture style.

  • Manual Básico de Consistência de Dados.Data Consistency Primer. Explica os problemas que são normalmente encontrados devido a uma consistência eventual entre os arquivos de dados de leitura e escrita ao utilizar o padrão CQRS e a forma como estes problemas podem ser resolvidos.Explains the issues that are typically encountered due to eventual consistency between the read and write data stores when using the CQRS pattern, and how these issues can be resolved.

  • Orientações sobre a Criação de Partições de Dados.Data Partitioning Guidance. Descreve como os arquivos de dados de leitura e escrita utilizados no padrão CQRS podem ser divididos em partições que podem ser geridas e acedidas separadamente para melhorar a escalabilidade, reduzir a contenção e otimizar o desempenho.Describes how the read and write data stores used in the CQRS pattern can be divided into partitions that can be managed and accessed separately to improve scalability, reduce contention, and optimize performance.

  • Padrão de Origem do Evento.Event Sourcing pattern. Descreve em maior detalhe como a Origem do Evento pode ser utilizada com o padrão CQRS para simplificar as tarefas em domínios complexos ao melhorar o desempenho, a escalabilidade e a capacidade de resposta.Describes in more detail how Event Sourcing can be used with the CQRS pattern to simplify tasks in complex domains while improving performance, scalability, and responsiveness. Bem como o fornecimento de consistência para os dados transacionais enquanto mantém registos de auditoria completos e um histórico que pode permitir ações de compensação.As well as how to provide consistency for transactional data while maintaining full audit trails and history that can enable compensating actions.

  • Padrão de Vista Materializada.Materialized View pattern. O modelo de leitura de uma implementação do CQRS pode conter vistas materializadas dos dados do modelo de escrita. Em alternativa, utilize o modelo de leitura para gerar vistas materializadas.The read model of a CQRS implementation can contain materialized views of the write model data, or the read model can be used to generate materialized views.

  • O guia de padrões e práticas CQRS Journey (Percurso CQRS).The patterns & practices guide CQRS Journey. Em particular, apresentando o padrão de segregação de responsabilidade de consulta do comando explora o padrão e quando é útil, e Epílogo: Lições aprendidas ajuda-o a compreender alguns dos problemas que surgem quando utiliza este padrão.In particular, Introducing the Command Query Responsibility Segregation pattern explores the pattern and when it's useful, and Epilogue: Lessons Learned helps you understand some of the issues that come up when using this pattern.

  • A publicação CQRS por Martin Fowler, que explica as noções básicas do padrão e ligações para outros recursos úteis.The post CQRS by Martin Fowler, which explains the basics of the pattern and links to other useful resources.