Muster „CQRS“ (Command and Query Responsibility Segregation)Command and Query Responsibility Segregation (CQRS) pattern

Das Muster „CQRS“ (Command and Query Responsibility Segregation) trennt Lese- und Aktualisierungsvorgänge für einen Datenspeicher.The Command and Query Responsibility Segregation (CQRS) pattern separates read and update operations for a data store. Das Implementieren von CQRS in Ihrer Anwendung kann die Leistung, Skalierbarkeit und Sicherheit maximieren.Implementing CQRS in your application can maximize its performance, scalability, and security. Die durch die Migration zu CQRS gewonnene Flexibilität ermöglicht es einem System, sich im Laufe der Zeit besser weiterzuentwickeln, und verhindert, dass Aktualisierungsbefehle auf Domänenebene Mergekonflikte verursachen.The flexibility created by migrating to CQRS allows a system to better evolve over time and prevents update commands from causing merge conflicts at the domain level.

Das ProblemThe problem

In herkömmlichen Architekturen wird zum Abfragen und Aktualisieren einer Datenbank das gleiche Datenmodell verwendet.In traditional architectures, the same data model is used to query and update a database. Dies ist eine einfache Vorgehensweise, die für grundlegende CRUD-Vorgänge gut geeignet ist.That's simple and works well for basic CRUD operations. Bei komplexeren Anwendungen kann dieser Ansatz aber zu Problemen führen.In more complex applications, however, this approach can become unwieldy. Beispielsweise werden von der Anwendung auf Leseseite unter Umständen unterschiedliche Abfragen durchgeführt und Datenübertragungsobjekte (Data Transfer Objects, DTOs) mit uneinheitlichen Formen zurückgegeben.For example, on the read side, the application may perform many different queries, returning data transfer objects (DTOs) with different shapes. Die Objektzuordnung kann kompliziert werden.Object mapping can become complicated. Auf der Schreibseite werden für das Modell ggf. eine komplexe Überprüfung und Geschäftslogik implementiert.On the write side, the model may implement complex validation and business logic. Hieraus kann sich ein Modell mit zu hoher Komplexität ergeben, das überdimensioniert ist.As a result, you can end up with an overly complex model that does too much.

Lese- und Schreibworkloads sind häufig asymmetrisch und verfügen über sehr unterschiedliche Leistungs- und Skalierungsanforderungen.Read and write workloads are often asymmetrical, with very different performance and scale requirements.

Konventionelle CRUD-Architektur

  • Dies führt häufig zu einem Konflikt zwischen den Lese- und Schreibdarstellungen der Daten, beispielsweise aufgrund zusätzlicher Spalten oder Eigenschaften, die ordnungsgemäß aktualisiert werden müssen, auch wenn sie im Rahmen eines Vorgangs nicht erforderlich sind.There is often 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.

  • Datenkonflikte können auftreten, wenn Vorgänge parallel für denselben Datensatz ausgeführt werden.Data contention can occur when operations are performed in parallel on the same set of data.

  • Die konventionelle Vorgehensweise kann sich negativ auf die Leistung auswirken, was auf die Auslastung im Datenspeicher und der Datenzugriffsschicht sowie die Komplexität der zum Abrufen von Informationen erforderlichen Abfragen zurückzuführen ist.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.

  • Die Verwaltung von Sicherheitsfeatures und Berechtigungen kann kompliziert werden, weil jede Entität sowohl Lese- als auch Schreibvorgängen unterworfen ist. Hierdurch werden Daten möglicherweise im falschen Kontext verfügbar gemacht.Managing security and permissions can become complex, because each entity is subject to both read and write operations, which might expose data in the wrong context.

LösungSolution

CQRS unterteilt Lese- und Schreibvorgänge in verschiedene Modelle und verwendet dafür Befehle zum Aktualisieren von Daten sowie Abfragen zum Lesen von Daten.CQRS separates reads and writes into different models, using commands to update data, and queries to read data.

  • Die Befehle sollten nicht datenzentriert, sondern aufgabenbasiert sein.Commands should be task based, rather than data centric. („Book hotel room“, nicht „set ReservationStatus to Reserved“).("Book hotel room", not "set ReservationStatus to Reserved").
  • Befehle können für die asynchrone Verarbeitung in eine Warteschlange gestellt werden, statt dass sie synchron verarbeitet werden.Commands may be placed on a queue for asynchronous processing, rather than being processed synchronously.
  • Mit Abfragen wird die Datenbank niemals geändert.Queries never modify the database. Eine Abfrage gibt ein DTO zurück, in dem kein Domänenwissen gekapselt ist.A query returns a DTO that does not encapsulate any domain knowledge.

Die Modelle können dann isoliert werden, wie im folgenden Diagramm dargestellt. Dies ist aber keine absolute Anforderung.The models can then be isolated, as shown in the following diagram, although that's not an absolute requirement.

Grundlegende CQRS-Architektur

Ein separates Abfrage- und Aktualisierungsmodell vereinfacht den Entwurf und die Implementierung.Having separate query and update models simplifies the design and implementation. Allerdings gibt es dabei den Nachteil, dass CQRS-Code nicht automatisch aus einem Datenbankschema generiert werden kann, indem Gerüstbaumechanismen wie O/RM-Tools verwendet werden.However, one disadvantage is that CQRS code can't automatically be generated from a database schema using scaffolding mechanisms such as O/RM tools.

Eine stärkere Isolation erzielen Sie, indem Sie die Lesedaten physisch von den Schreibdaten trennen.For greater isolation, you can physically separate the read data from the write data. In diesem Fall kann die Lesedatenbank ihr eigenes Datenschema verwenden, das für Abfragen optimiert ist.In that case, the read database can use its own data schema that is optimized for queries. Beispielsweise kann eine materialisierte Sicht der Daten gespeichert werden, um komplexe Verknüpfungen oder O/RM-Zuordnungen zu vermeiden.For example, it can store a materialized view of the data, in order to avoid complex joins or complex O/RM mappings. Es kann sogar ein anderer Typ von Datenspeicher verwendet werden.It might even use a different type of data store. Die Schreibdatenbank kann beispielsweise relational sein, während es sich bei der Lesedatenbank um eine Dokumentdatenbank handelt.For example, the write database might be relational, while the read database is a document database.

Wenn separate Lese- und Schreibdatenbanken verwendet werden, müssen sie synchron gehalten werden. Dies wird normalerweise erreicht, indem das Schreibmodell jeweils ein Ereignis veröffentlicht, wenn es die Datenbank aktualisiert.If separate read and write databases are used, they must be kept in sync. Typically this is accomplished by having the write model publish an event whenever it updates the database. Die Aktualisierung der Datenbank und die Veröffentlichung des Ereignisses müssen in einer einzelnen Transaktion durchgeführt werden.Updating the database and publishing the event must occur in a single transaction.

CQRS-Architektur mit separaten Speichern für Lese- und Schreibvorgänge

Beim Speicher für Lesevorgänge kann es sich um ein schreibgeschütztes Replikat des Speichers für Schreibvorgänge handeln. Anderenfalls können Speicher für Lese- und Schreibvorgänge grundlegend verschiedene Strukturen aufweisen.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. Die Verwendung mehrerer schreibgeschützter Replikate kann die Abfrageleistung erhöhen – insbesondere in verteilten Szenarien, in denen sich schreibgeschützte Replikate in der Nähe der Anwendungsinstanzen befinden.Using multiple read-only replicas can increase query performance, especially in distributed scenarios where read-only replicas are located close to the application instances.

Durch die Trennung von Speichern für Lese- und Schreibvorgänge kann können beide Speicher entsprechend der Auslastung skaliert werden.Separation of the read and write stores also allows each to be scaled appropriately to match the load. Beispielsweise ist in Speichern für Lesevorgänge in der Regel eine weitaus höhere Auslastung anzutreffen als bei Speichern für Schreibvorgänge.For example, read stores typically encounter a much higher load than write stores.

Für einige Implementierungen von CQRS wird das Muster „Event Sourcing“ verwendet.Some implementations of CQRS use the Event Sourcing pattern. Bei diesem Muster wird der Anwendungsstatus als Ereignissequenz gespeichert.With this pattern, application state is stored as a sequence of events. Jedes Ereignis umfasst eine Reihe von Änderungen der Daten.Each event represents a set of changes to the data. Der aktuelle Zustand wird hergestellt, indem die Ereignisse erneut durchgeführt werden.The current state is constructed by replaying the events. In einem CQRS-Kontext besteht ein Vorteil der Ereignisherkunftsermittlung darin, dass dieselben Ereignisse verwendet werden können, um andere Komponenten zu benachrichtigen, z.B. vor allem das Lesemodell.In a CQRS context, one benefit of Event Sourcing is that the same events can be used to notify other components — in particular, to notify the read model. Im Lesemodell werden die Ereignisse genutzt, um eine Momentaufnahme des aktuellen Zustands zu erstellen, da dies für Abfragen effizienter ist.The read model uses the events to create a snapshot of the current state, which is more efficient for queries. Mit der Ereignisherkunftsermittlung erhöht sich aber auch die Komplexität des Designs.However, Event Sourcing adds complexity to the design.

Zu den Vorteilen von CQRS gehören folgende:Benefits of CQRS include:

  • Unabhängige Skalierung.Independent scaling. CQRS ermöglicht das unabhängige Skalieren der Lese- und Schreibworkloads und kann zu einer Verringerung von Sperrkonflikten führen.CQRS allows the read and write workloads to scale independently, and may result in fewer lock contentions.
  • Optimierte Datenschemas:Optimized data schemas. Auf der Leseseite kann ein Schema verwendet werden, das für Abfragen optimiert ist, während auf der Schreibseite ein Schema verwendet wird, das für Updates optimiert ist.The read side can use a schema that is optimized for queries, while the write side uses a schema that is optimized for updates.
  • Sicherheit.Security. Es ist einfacher sicherzustellen, dass nur die richtigen Domänenentitäten Schreibvorgänge für die Daten durchführen.It's easier to ensure that only the right domain entities are performing writes on the data.
  • Trennung von Zuständigkeiten:Separation of concerns. Das Trennen der Lese- und Schreibseite kann zu Modellen führen, die besser gewartet werden können und flexibler sind.Segregating the read and write sides can result in models that are more maintainable and flexible. Der größte Teil der komplexen Geschäftslogik betrifft das Schreibmodell.Most of the complex business logic goes into the write model. Das Lesemodell kann relativ einfach gestaltet sein.The read model can be relatively simple.
  • Einfachere Abfragen:Simpler queries. Indem eine materialisierte Sicht in der Lesedatenbank gespeichert wird, kann die Anwendung beim Durchführen von Abfragen komplexe Verknüpfungen vermeiden.By storing a materialized view in the read database, the application can avoid complex joins when querying.

Probleme und Überlegungen bei der ImplementierungImplementation issues and considerations

Bei der Implementierung dieses Musters gibt es u.a. folgende Herausforderungen:Some challenges of implementing this pattern include:

  • Komplexität.Complexity. Die Grundidee von CQRS ist einfach.The basic idea of CQRS is simple. Es kann sich aber auch ein komplexeres Anwendungsdesign ergeben, z.B. bei Verwendung des Musters für die Ereignisherkunftsermittlung.But it can lead to a more complex application design, especially if they include the Event Sourcing pattern.

  • Messaging:Messaging. Für CQRS wird zwar kein Messaging benötigt, aber es wird trotzdem häufig genutzt, um Befehle zu verarbeiten und Aktualisierungsereignisse zu veröffentlichen.Although CQRS does not require messaging, it's common to use messaging to process commands and publish update events. In diesem Fall muss die Anwendung Nachrichtenfehler oder doppelte Nachrichten verarbeiten können.In that case, the application must handle message failures or duplicate messages.

  • Letztliche Konsistenz:Eventual consistency. Wenn Sie die Lese- und Schreibdatenbanken trennen, kann es sein, dass die Lesedaten veraltet sind.If you separate the read and write databases, the read data may be stale. Der Speicher mit dem Lesemodell muss aktualisiert werden, damit Änderungen am Speicher mit dem Schreibmodell übernommen werden. Außerdem kann es schwierig sein, basierend auf veralteten Lesedaten festzustellen, wann ein Benutzer eine Anforderung gestellt hat.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.

Verwendung dieses MustersWhen to use this pattern

Ziehen Sie CQRS für die folgenden Szenarios in Erwägung:Consider CQRS for the following scenarios:

  • Kollaborative Domänen, bei denen viele Benutzer parallel auf dieselben Daten zugreifen.Collaborative domains where many users access the same data in parallel. Mithilfe von CQRS können Sie Befehle mit ausreichender Granularität definieren, um Zusammenführungskonflikte auf Domänenebene zu minimieren, und auftretende Konflikte können per Befehl zusammengeführt werden.CQRS allows you to define commands with enough granularity to minimize merge conflicts at the domain level, and conflicts that do arise can be merged by the command.

  • Bei taskbasierten Benutzeroberflächen, bei denen Benutzer in mehreren Schritten oder mit komplexen Domänenmodellen durch einen komplizierten Prozess geführt werden.Task-based user interfaces where users are guided through a complex process as a series of steps or with complex domain models. Das Schreibmodell verfügt über einen vollständigen Befehlsverarbeitungsstapel mit Geschäftslogik, Eingabeüberprüfung und Geschäftsvalidierung.The write model has a full command-processing stack with business logic, input validation, and business validation. Das Schreibmodell behandelt möglicherweise einen Satz zugeordneter Objekte als einzelne Einheit für Datenänderungen (ein „Aggregat“ in der DDD-Terminologie) und stellt sicher, dass sich diese Objekte immer in einem konsistenten Zustand befinden.The write model may treat a set of associated objects as a single unit for data changes (an aggregate, in DDD terminology) and ensure that these objects are always in a consistent state. Das Lesemodell weist weder eine Geschäftslogik noch einen Validierungsstapel auf und gibt nur ein DTO zur Verwendung in einem Anzeigemodell zurück.The read model has no business logic or validation stack, and just returns a DTO for use in a view model. Das Lesemodell ist letztlich konsistent mit dem Schreibmodell.The read model is eventually consistent with the write model.

  • Szenarios, in denen die Leistung von Datenlesevorgängen separat von der Leistung von Datenschreibvorgängen optimiert werden muss – insbesondere dann, wenn die Anzahl der Lesevorgänge wesentlich größer ist als die Anzahl der Schreibvorgänge ist.Scenarios where performance of data reads must be fine tuned separately from performance of data writes, especially when the number of reads is much greater than the number of writes. In diesem Szenario können Sie das Lesemodell aufskalieren, das Schreibmodell aber nur auf einigen wenigen Instanzen ausführen.In this scenario, you can scale out the read model, but run the write model on just a few instances. Die Verwendung einer kleinen Anzahl von Schreibmodellinstanzen kann auch das Auftreten von Zusammenführungskonflikten minimieren.A small number of write model instances also helps to minimize the occurrence of merge conflicts.

  • In Szenarien, in denen sich ein Entwicklerteam auf das komplexe Domänenmodell als Teil des Schreibmodells konzentrieren kann, während sich ein anderes Team auf das Lesemodell und die Benutzeroberflächen konzentrieren kann.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.

  • In Szenarien, in denen das System voraussichtlich im Laufe der Zeit weiterentwickelt wird und mehrere Versionen des Modells enthalten kann oder in denen sich Geschäftsregeln regelmäßig ändern.Scenarios where the system is expected to evolve over time and might contain multiple versions of the model, or where business rules change regularly.

  • Bei der Integration in andere Systeme, insbesondere in Kombination mit Ereignisquellen, bei denen der vorübergehende Ausfall eines Subsystems nicht die Verfügbarkeit der anderen Systeme beeinträchtigen soll.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.

Verwenden Sie dieses Muster in folgenden Fällen nicht:This pattern isn't recommended when:

  • Die Domäne oder die Geschäftsregeln sind einfach.The domain or the business rules are simple.

  • Eine einfache Benutzeroberfläche im CRUD-Stil und Datenzugriffsvorgänge reichen aus.A simple CRUD-style user interface and data access operations are sufficient.

Es wird empfohlen, CQRS auf bestimmte Bereiche Ihres Systems anzuwenden, wo es den größten Nutzen bietet.Consider applying CQRS to limited sections of your system where it will be most valuable.

Ereignisherkunftsermittlung und CQRSEvent Sourcing and CQRS

Das Muster „CQRS“ wird häufig zusammen mit dem Muster „Ereignisherkunftsermittlung“ verwendet.The CQRS pattern is often used along with the Event Sourcing pattern. CQRS-basierte Systeme verwenden getrennte Lese- und Schreibdatenmodelle, die auf ihre jeweiligen Tasks zugeschnitten sind und sich häufig in räumlich getrennten Speichern befinden.CQRS-based systems use separate read and write data models, each tailored to relevant tasks and often located in physically separate stores. Bei Verwendung mit dem Muster Ereignisherkunftsermittlung ist der Ereignisspeicher das Schreibmodell und stellt die offizielle Informationsquelle dar.When used with the Event Sourcing pattern, the store of events is the write model, and is the official source of information. Das Lesemodell eines CQRS-basierten Systems bietet materialisierte Sichten der Daten, üblicherweise in Form von hochgradig denormalisierten Sichten.The read model of a CQRS-based system provides materialized views of the data, typically as highly denormalized views. Diese Sichten sind auf die Schnittstellen und die Anzeigeanforderungen der Anwendung zugeschnitten, wodurch sowohl die Anzeige- als auch die Abfrageleistung maximiert werden können.These views are tailored to the interfaces and display requirements of the application, which helps to maximize both display and query performance.

Durch die Verwendung des Ereignisdatenstroms als Speicher für Schreibvorgänge anstelle der eigentlichen Daten zu einem bestimmten Zeitpunkt werden Aktualisierungskonflikte in einem einzigen Aggregat vermieden und die Leistung sowie Skalierbarkeit maximiert.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. Mit den Ereignissen können materialisierte Sichten der Daten asynchron generiert werden, mit denen Speicher für Lesevorgänge aufgefüllt werden.The events can be used to asynchronously generate materialized views of the data that are used to populate the read store.

Da der Ereignisspeicher die offizielle Informationsquelle darstellt, ist es möglich, die materialisierten Sichten zu löschen und alle vergangenen Ereignisse erneut wiederzugeben, um eine neue Darstellung des aktuellen Zustands zu erstellen, wenn das System weiterentwickelt wird oder das Lesemodell geändert werden muss.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. Bei den materialisierten Sichten handelt es sich praktisch um einen zuverlässigen schreibgeschützten Datencache.The materialized views are in effect a durable read-only cache of the data.

Bei der Verwendung von CQRS in Kombination mit dem Muster „Ereignisherkunftsermittlung“ sollten Sie Folgendes beachten:When using CQRS combined with the Event Sourcing pattern, consider the following:

  • Wie bei jedem System, bei dem die Speicher für Lese- und Schreibvorgänge getrennt sind, sind die Systeme, die auf diesem Muster basieren, nur letztlich konsistent.As with any system where the write and read stores are separate, systems based on this pattern are only eventually consistent. Zwischen der Generierung des Ereignisses und der Aktualisierung des Datenspeichers wird eine gewisse Verzögerung auftreten.There will be some delay between the event being generated and the data store being updated.

  • Das Muster erhöht die Komplexität, da Codes erstellt werden müssen, um Ereignisse zu initiieren und zu verarbeiten und die entsprechenden Ansichten oder Objekte, die für das Abfrage- oder Lesemodell erforderlich sind, zusammenzustellen oder zu aktualisieren.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. Die Komplexität des Musters „CQRS“ in Verbindung mit dem Muster für die Ereignisherkunftsermittlung kann eine erfolgreiche Implementierung erschweren und erfordert eine andere Herangehensweise beim Entwurf von Systemen.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. Die Ereignisherkunftsermittlung kann jedoch die Modellierung der Domäne vereinfachen. Zudem vereinfacht es das erneute Generieren von Ansichten oder Erstellen neuer Ansichten, da die Änderungsabsicht in den Daten erhalten bleibt.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.

  • Die Generierung materialisierter Sichten für die Verwendung im Lesemodell oder in Projektionen der Daten durch Wiedergabe und Verarbeitung der Ereignisse für bestimmte Entitäten oder Sammlungen von Entitäten kann eine enorme Verarbeitungszeit und einen immensen Ressourcenverbrauch zur Folge haben.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. Dies gilt insbesondere dann, wenn Werte über lange Zeiträume zu summieren oder zu analysieren sind, da eventuell alle zugehörigen Ereignisse untersucht werden müssen.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. Dies lässt sich durch die Implementierung von Momentaufnahmen der Daten in geplanten Intervallen lösen, wie etwa der Gesamtzahl aufgetretener Aktionen oder des aktuellen Zustands einer Entität.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.

BeispielExample

Der folgende Code zeigt einige Auszüge aus einem Beispiel einer CQRS-Implementierung, in der unterschiedliche Definitionen für das Lese- und das Schreibmodell verwendet werden.The following code shows some extracts from an example of a CQRS implementation that uses different definitions for the read and the write models. Die Modellschnittstellen legen keine Features der zugrundeliegenden Datenspeicher fest und können unabhängig voneinander weiterentwickelt und angepasst werden, da diese Schnittstellen getrennt sind.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.

Der folgende Code zeigt die Definition des Lesemodells.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; }
  }
}

Das System ermöglicht den Benutzern, Produkte zu bewerten.The system allows users to rate products. Hierfür wird im Anwendungscode der Befehl RateProduct verwendet, wie im folgenden Code zu sehen ist.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; }
}

Das System verwendet die Klasse ProductsCommandHandler, um die von der Anwendung gesendeten Befehle zu verarbeiten.The system uses the ProductsCommandHandler class to handle commands sent by the application. Clients senden Befehle üblicherweise über ein Messagingsystem wie eine Warteschlange an die Domäne.Clients typically send commands to the domain through a messaging system such as a queue. Der Befehlshandler akzeptiert diese Befehle und ruft Methoden der Domänenschnittstelle auf.The command handler accepts these commands and invokes methods of the domain interface. Die Granularität der einzelnen Befehle ist darauf ausgelegt, die Wahrscheinlichkeit von in Konflikt stehenden Anforderungen zu verringern.The granularity of each command is designed to reduce the chance of conflicting requests. Der folgende Code zeigt eine Gliederung der Klasse 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)
  {
    ...
  }
}

Die folgenden Muster und Anweisungen könnten für die Implementierung dieses Musters relevant sein:The following patterns and guidance are useful when implementing this pattern:

  • Data Consistency Primer (Grundlagen der Datenkonsistenz).Data Consistency Primer. In diesem Artikel werden die Probleme, die typischerweise aufgrund von letztlicher Konsistenz zwischen den Speichern für Lese- und Schreibvorgänge bei der Verwendung des Musters „CQRS“ auftreten, sowie Möglichkeiten zur Behandlung dieser Probleme erklärt.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.

  • Data Partitioning Guidance (Leitfaden zur Datenpartitionierung).Data Partitioning Guidance. Beschreibt bewährte Methoden für das Aufteilen von Daten in Partitionen, die separat verwaltet und aufgerufen werden können, um die Skalierbarkeit zu verbessern, Konflikte zu reduzieren und die Leistung zu optimieren.Describes best practices for dividing data into partitions that can be managed and accessed separately to improve scalability, reduce contention, and optimize performance.

  • Muster für Ereignisherkunftsermittlung.Event Sourcing pattern. In diesem Artikel wird ausführlich beschrieben, wie das Muster „CQRS“ mithilfe der Ereignisherkunftsermittlung eingesetzt werden kann, um Tasks in komplexen Domänen zu vereinfachen und gleichzeitig die Leistung, Skalierbarkeit und Reaktionsfähigkeit zu verbessern.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. Außerdem erfahren Sie, wie Sie die Konsistenz von Transaktionsdaten sicherstellen und gleichzeitig vollständige Audit-Trails und Überwachungsverläufe erstellen können, die kompensierende Maßnahmen ermöglichen.As well as how to provide consistency for transactional data while maintaining full audit trails and history that can enable compensating actions.

  • Muster „Materialisierte Sichten“:Materialized View pattern. Das Lesemodell einer CQRS-Implementierung kann materialisierte Sichten der Daten des Schreibmodells enthalten. Das Modell kann alternativ auch zur Generierung materialisierter Sichten verwendet werden.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.

  • Muster und Vorgehensweisen zu CQRS:The patterns & practices guide CQRS Journey. Unter Reference 2: Introducing the Command Query Responsibility Segregation Pattern (Referenz 2: Einführung in das Muster „Command and Query Responsibility Segregation“) wird insbesondere das Muster beschrieben und außerdem erläutert, wann die Nutzung sinnvoll ist. Unter Epilogue: Lessons Learned (Epilog: Erkenntnisse) werden einige Probleme beschrieben, die bei Verwendung dieses Musters auftreten können.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.

  • In dem Beitrag CQRS von Martin Fowler werden die Grundlagen des Musters erklärt und Links zu anderen nützlichen Ressourcen angegeben.The post CQRS by Martin Fowler, which explains the basics of the pattern and links to other useful resources.