CQRS là một architectural pattern tách biệt operations đọc (read/queries) và ghi (write/commands) thành hai models riêng biệt. Điều này cho phép tối ưu hóa mỗi side một cách độc lập về performance, scalability, và security.
// Commands - Change state
public class CreateOrderCommand : ICommand
{
public Guid CustomerId { get; set; }
public List<OrderItemDto> Items { get; set; }
}
public class UpdateOrderStatusCommand : ICommand
{
public Guid OrderId { get; set; }
public OrderStatus NewStatus { get; set; }
}
// Queries - Read data
public class GetOrderByIdQuery : IQuery<OrderDto>
{
public Guid OrderId { get; set; }
}
public class GetCustomerOrdersQuery : IQuery<List<OrderSummaryDto>>
{
public Guid CustomerId { get; set; }
}
// Write Model - Domain-focused
public class Order
{
public Guid Id { get; private set; }
public Guid CustomerId { get; private set; }
public List<OrderItem> Items { get; private set; }
public OrderStatus Status { get; private set; }
public void AddItem(Product product, int quantity)
{
// Domain logic
}
public void Place()
{
// Business rules
Status = OrderStatus.Placed;
}
}
// Read Model - UI/Presentation-focused
public class OrderDto
{
public Guid Id { get; set; }
public string CustomerName { get; set; }
public List<OrderItemDto> Items { get; set; }
public decimal TotalAmount { get; set; }
public string StatusDisplay { get; set; }
public string FormattedOrderDate { get; set; }
}
public class OrderSummaryDto // Lightweight for lists
{
public Guid Id { get; set; }
public string CustomerName { get; set; }
public decimal TotalAmount { get; set; }
public string Status { get; set; }
}
public class CreateOrderHandler
{
public async Task<Result> HandleAsync(CreateOrderCommand command)
{
// Write to main database
var order = new Order(command.CustomerId);
await _writeRepository.AddAsync(order);
// Immediately update read database
await _readRepository.InsertAsync(MapToReadModel(order));
return Result.Success(order.Id);
}
}
// Write to event store
public class CreateOrderHandler
{
public async Task<Result> HandleAsync(CreateOrderCommand command)
{
var order = new Order(command.CustomerId);
await _orderRepository.AddAsync(order);
// Publish event
await _eventBus.PublishAsync(new OrderCreatedEvent(order));
}
}
// Event handler updates read database
public class OrderCreatedEventHandler : IEventHandler<OrderCreatedEvent>
{
private readonly IOrderReadRepository _readRepository;
public async Task HandleAsync(OrderCreatedEvent evt)
{
var readModel = new OrderDto
{
Id = evt.Order.Id,
// ... map fields
};
await _readRepository.InsertAsync(readModel);
}
}