Фильтрация запросов 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;
}