CQRS (Command Query Responsibility Segregation) — это паттерн проектирования, разделяющий операции чтения (Query) и записи (Command) данных. Такой подход позволяет повысить производительность, масштабируемость и безопасность приложения, особенно при работе с высоконагруженными системами.
Основные принципы CQRS
- Разделение команд и запросов. Операции, изменяющие состояние системы, отделены от операций, которые просто возвращают данные.
- Разные модели данных. Для команд и запросов могут использоваться разные модели данных и даже разные хранилища.
- Обработка команд через обработчики. Каждая команда (Command) передаётся в отдельный обработчик, который выполняет бизнес-логику.
- Чтение через запросы. Запросы (Query) могут обращаться напрямую к базе данных или использовать кэш для ускорения работы.
Реализация CQRS в C#
В C# реализация CQRS часто строится с использованием библиотек, таких как MediatR, которая упрощает обработку команд и запросов.
Определение команды (Command)
public class CreateUserCommand : IRequest<int>
{
public string Name { get; set; }
public string Email { get; set; }
}
Обработчик команды
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, int>
{
private readonly AppDbContext _dbContext;
public CreateUserCommandHandler(AppDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<int> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
var user = new User { Name = request.Name, Email = request.Email };
_dbContext.Users.Add(user);
await _dbContext.SaveChangesAsync(cancellationToken);
return user.Id;
}
}
Определение запроса (Query)
public class GetUserByIdQuery : IRequest<UserDto>
{
public int Id { get; set; }
}
Обработчик запроса
public class GetUserByIdQueryHandler : IRequestHandler<GetUserByIdQuery, UserDto>
{
private readonly AppDbContext _dbContext;
public GetUserByIdQueryHandler(AppDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<UserDto> Handle(GetUserByIdQuery request, CancellationToken cancellationToken)
{
var user = await _dbContext.Users.FindAsync(request.Id);
return user != null ? new UserDto { Id = user.Id, Name = user.Name, Email = user.Email } : null;
}
}
Преимущества и недостатки CQRS
Преимущества
- Улучшенная производительность за счёт раздельных моделей чтения и записи.
- Гибкость и масштабируемость системы.
- Повышенная безопасность, так как команды могут проверять права доступа перед выполнением.
Недостатки
- Усложнение архитектуры приложения.
- Требует дополнительных механизмов синхронизации данных между моделями команд и запросов.