In CQRS, a command is a message that represents an intent to perform a specific action or operation. It encapsulates all the necessary information to perform the operation, such as the parameters required for the operation, the identity of the user or system that initiated the command, and any context or metadata that may be relevant. A command does not represent the result of the operation, but rather the intent to perform the operation. It is typically sent to the command side of a CQRS system, which is responsible for validating the command, executing the operation, and updating the system’s state accordingly.
Example
Let’s say we have an e-commerce system that allows users to place orders. A command in this context could be PlaceOrderCommand, which represents the intention of a user to place an order. The PlaceOrderCommand would typically contain information such as the products being ordered, the quantities, the billing and shipping addresses, and any other relevant details.
Here’s an example of what the PlaceOrderCommand class might look like in Java:
public class PlaceOrderCommand {
private List<Product> products;
private Address billingAddress;
private Address shippingAddress;
public PlaceOrderCommand(List<Product> products, Address billingAddress, Address shippingAddress) {
this.products = products;
this.billingAddress = billingAddress;
this.shippingAddress = shippingAddress;
}
// getters and setters for the fields
}
Once a user submits the PlaceOrderCommand, it would be handled by the command handler, which would validate the command, create a new Order aggregate, and apply the necessary domain events to represent the order being placed.
Use with event sourcing
When used in conjunction with event sourcing, command handling involves receiving and processing commands, updating the state of an aggregate by generating events, and persisting those events to an event store. The events are then published to an event bus for consumption by event handlers.
The command handler receives a command, validates it, and loads the appropriate aggregate from the event store. The aggregate then processes the command, generating one or more events that describe the changes made to its state. These events are then persisted to the event store, and published to the event bus.
Event handlers that are subscribed to the relevant event types can then perform their own operations, such as updating read models or invoking downstream services.
Here is an example of a command handler that works with an event-sourced aggregate in Java:
public class OrderCommandHandler {
private final EventStore eventStore;
public OrderCommandHandler(EventStore eventStore) {
this.eventStore = eventStore;
}
public void handle(PlaceOrderCommand command) {
OrderId orderId = command.getOrderId();
Order order = eventStore.get(Order.class, orderId);
order.place(command.getCustomerName(), command.getOrderItems());
eventStore.save(order.getUncommittedChanges());
}
}
In this example, the OrderCommandHandler receives a PlaceOrderCommand and loads the corresponding Order aggregate from the event store using its ID. The place method of the Order aggregate then processes the command, generating an event that describes the order being placed. The uncommitted changes of the aggregate are then saved to the event store, which persists the new event.