142 lines
3.5 KiB
Markdown
142 lines
3.5 KiB
Markdown
# CQRS Layer
|
|
|
|
Implement commands, queries, and handlers.
|
|
|
|
## Create Command
|
|
|
|
```csharp
|
|
// OrderManagement.CQRS/Commands/PlaceOrderCommand.cs
|
|
namespace OrderManagement.CQRS.Commands;
|
|
|
|
public record PlaceOrderCommand
|
|
{
|
|
public int CustomerId { get; init; }
|
|
public List<OrderItemDto> Items { get; init; } = new();
|
|
}
|
|
|
|
public record OrderItemDto
|
|
{
|
|
public int ProductId { get; init; }
|
|
public string ProductName { get; init; } = string.Empty;
|
|
public int Quantity { get; init; }
|
|
public decimal Price { get; init; }
|
|
}
|
|
```
|
|
|
|
## Command Handler
|
|
|
|
```csharp
|
|
// OrderManagement.CQRS/Commands/PlaceOrderCommandHandler.cs
|
|
using Svrnty.CQRS.Abstractions;
|
|
using OrderManagement.Domain.Entities;
|
|
|
|
namespace OrderManagement.CQRS.Commands;
|
|
|
|
public class PlaceOrderCommandHandler : ICommandHandler<PlaceOrderCommand, int>
|
|
{
|
|
private readonly IOrderRepository _repository;
|
|
|
|
public PlaceOrderCommandHandler(IOrderRepository repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
public async Task<int> HandleAsync(PlaceOrderCommand command, CancellationToken ct)
|
|
{
|
|
var items = command.Items.Select(i => new OrderItem
|
|
{
|
|
ProductId = i.ProductId,
|
|
ProductName = i.ProductName,
|
|
Quantity = i.Quantity,
|
|
Price = i.Price
|
|
}).ToList();
|
|
|
|
var order = Order.Create(command.CustomerId, items);
|
|
|
|
await _repository.AddAsync(order, ct);
|
|
await _repository.SaveChangesAsync(ct);
|
|
|
|
return order.Id;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Validator
|
|
|
|
```csharp
|
|
// OrderManagement.CQRS/Validators/PlaceOrderCommandValidator.cs
|
|
using FluentValidation;
|
|
|
|
namespace OrderManagement.CQRS.Validators;
|
|
|
|
public class PlaceOrderCommandValidator : AbstractValidator<PlaceOrderCommand>
|
|
{
|
|
public PlaceOrderCommandValidator()
|
|
{
|
|
RuleFor(x => x.CustomerId).GreaterThan(0);
|
|
RuleFor(x => x.Items).NotEmpty();
|
|
RuleForEach(x => x.Items).ChildRules(item =>
|
|
{
|
|
item.RuleFor(x => x.ProductId).GreaterThan(0);
|
|
item.RuleFor(x => x.Quantity).GreaterThan(0);
|
|
item.RuleFor(x => x.Price).GreaterThan(0);
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
## Query
|
|
|
|
```csharp
|
|
// OrderManagement.CQRS/Queries/GetOrderQuery.cs
|
|
public record GetOrderQuery
|
|
{
|
|
public int OrderId { get; init; }
|
|
}
|
|
|
|
public record OrderDto
|
|
{
|
|
public int Id { get; init; }
|
|
public int CustomerId { get; init; }
|
|
public string Status { get; init; } = string.Empty;
|
|
public decimal TotalAmount { get; init; }
|
|
public DateTimeOffset PlacedAt { get; init; }
|
|
public List<OrderItemDto> Items { get; init; } = new();
|
|
}
|
|
```
|
|
|
|
## Query Handler
|
|
|
|
```csharp
|
|
// OrderManagement.CQRS/Queries/GetOrderQueryHandler.cs
|
|
public class GetOrderQueryHandler : IQueryHandler<GetOrderQuery, OrderDto>
|
|
{
|
|
private readonly IOrderRepository _repository;
|
|
|
|
public async Task<OrderDto> HandleAsync(GetOrderQuery query, CancellationToken ct)
|
|
{
|
|
var order = await _repository.GetByIdAsync(query.OrderId, ct);
|
|
|
|
return new OrderDto
|
|
{
|
|
Id = order.Id,
|
|
CustomerId = order.CustomerId,
|
|
Status = order.Status.ToString(),
|
|
TotalAmount = order.TotalAmount,
|
|
PlacedAt = order.PlacedAt,
|
|
Items = order.Items.Select(i => new OrderItemDto
|
|
{
|
|
ProductId = i.ProductId,
|
|
ProductName = i.ProductName,
|
|
Quantity = i.Quantity,
|
|
Price = i.Price
|
|
}).ToList()
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
Continue to [DAL Layer](04-dal-layer.md)
|