Что такое CQRS в C#

CQRS (Command Query Responsibility Segregation) — это паттерн проектирования, разделяющий операции чтения (Query) и записи (Command) данных. Такой подход позволяет повысить производительность, масштабируемость и безопасность приложения, особенно при работе с высоконагруженными системами.

Основные принципы CQRS

  1. Разделение команд и запросов. Операции, изменяющие состояние системы, отделены от операций, которые просто возвращают данные.
  2. Разные модели данных. Для команд и запросов могут использоваться разные модели данных и даже разные хранилища.
  3. Обработка команд через обработчики. Каждая команда (Command) передаётся в отдельный обработчик, который выполняет бизнес-логику.
  4. Чтение через запросы. Запросы (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

Преимущества

  • Улучшенная производительность за счёт раздельных моделей чтения и записи.
  • Гибкость и масштабируемость системы.
  • Повышенная безопасность, так как команды могут проверять права доступа перед выполнением.

Недостатки

  • Усложнение архитектуры приложения.
  • Требует дополнительных механизмов синхронизации данных между моделями команд и запросов.