Фильтрация запросов DDD, CQRS и Mediatr

Я работаю над проектом по шаблонам CQRS и Mediatr.

У меня есть объект, настроенный так

    public class Order
{
    public Guid OrderId { get; set; }

    public Guid CreatedByUserId { get; set; }

    public Guid? AcceptedByUserId { get; set; }

    public string Registration { get; set; }

    public string Description { get; set; }

    public User CreatedByUser { get; set; }
    public User AcceptedByUser { get; set; }
}

Когда я пишу мои 2 запроса GetAllOrdersCreatedByUser & GetAllOrdersAcceptedByUser, весь код практически одинаков.

Единственное исключение из этого - в созданном запросе my where на CreatedByUserId и моем принятом запросе где на AcceptedByUserId

GetAllOrdersAcceptedByUser: -

        public async Task<OrderAcceptedByUserListViewModel> Handle(GetAllOrdersAcceptedByUserQuery request, CancellationToken cancellationToken)
    {
        var model = new OrderAcceptedByUserListViewModel
        {
            Orders = await _context.Order
            .Where(x => x.AcceptedByUserId == request.UserId)
            .Select(OrderDto.Projection)
            .OrderBy(o => o.Registration)
            .ToListAsync(cancellationToken)
        };

        return model;
    }

GetAllOrdersCreatedByUser: -

        public async Task<OrderCreatedByUserListViewModel> Handle(GetAllOrdersCreatedByUserQuery request, CancellationToken cancellationToken)
    {
        var model = new OrderCreatedByUserListViewModel
        {
            Orders = await _context.Order
            .Where(x => x.CreatedByUserId == request.UserId)
            .Select(OrderDto.Projection)
            .OrderBy(o => o.Registration)
            .ToListAsync(cancellationToken)
        };

        return model;
    }

Это правильная реализация или объективно лучше иметь 1 запрос, который может выполнять оба в зависимости от того, как он вызывается из контроллера?

Изменить: добавлены лучшие теги

2 ответа

Запросы могут оставаться отдельными (поэтому они следуют SOLID), и вы можете избежать дублирования кода другими способами. Может быть, попробуйте извлечь повторяющуюся часть запроса, чтобы получить заказы без их фильтрации, используя where в virtual сначала метод и затем отфильтруйте их в соответствующих запросах.

Вы можете применить шаблон спецификации к запросам, то есть к одному запросу с предикатом в качестве аргумента.

Но DDD поощряет использование вездесущего языка, и если ваши пользователи говорят не с помощью предикатов, а с именами конкретных методов, я бы предложил пользователю 2 запроса, а затем, если вы не хотите повторять код, оба запроса будут вызывать общий запрос с использованием предикатов.

Прежде всего, слияния классов GetAllOrdersCreatedByUserQuery а также GetAllOrdersAcceptedByUserQuery

Смотрите следующий класс для справки:

public class GetAllOrdersByUserQuery :  : IRequest<OrdeListViewModel>
{
    // if OrderAcceptedByUser is true else OrderCreatedByUser = false
    public bool AcceptedOrCreatedBit { get; set; } 
    public string UserId { get; set; }
}

А также посмотреть модель для OrderCreatedByUserListViewModel and OrderCreatedByUserListViewModel

См. Следующую модель просмотра для справки:

public class OrdeListViewModel
{
    public List<Order> Orders { get; set; }
}

И, наконец, ваш метод обработки MediatR должен быть таким:

public async Task<OrdeListViewModel> Handle(GetAllOrdersByUserQuery request, CancellationToken cancellationToken)
{
    OrdeListViewModel model = new OrdeListViewModel();
    if (request.AcceptedOrCreatedBit) // true for OrderAcceptedByUser
    {

            model.Orders = await _context.Order
            .Where(x => x.AcceptedByUserId == request.UserId)
            .Select(OrderDto.Projection)
            .OrderBy(o => o.Registration)
            .ToListAsync(cancellationToken)

    }
    else // false for OrderCreatedByUser
    {

            model.Orders = await _context.Order
            .Where(x => x.CreatedByUserId == request.UserId)
            .Select(OrderDto.Projection)
            .OrderBy(o => o.Registration)
            .ToListAsync(cancellationToken)

    }

    return model;
}
Другие вопросы по тегам