0

I am working on a project following CQRS and Mediatr pattern.

I have an entity set up like this

    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; }
}

When i'm writing my 2 queries GetAllOrdersCreatedByUser & GetAllOrdersAcceptedByUser all the code is virtually the same.

The only exception to that is on the Created query my where is on CreatedByUserId and my Accepted query where is on 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;
    }

Is this the correct implementation or is it objectively better to have 1 query that can do both depending on how its called from the controller?

Edit: Added better tags

3 Answers3

1

The queries could stay separate (so they follow SOLID) and you could avoid code duplication by some other means. Maybe try extracting the recurring part of the query to get the orders without filtering them using where in a virtual method first and filter then them in the respective queries.

Kizivat
  • 183
  • 3
  • 14
1

You could apply specification pattern to queries, i.e., one query with a predicate as argument.

But DDD promotes to use an ubiquitous language, and if your users don't speak using predicates, but concrete methods names, I would offer to the user 2 queries, and then if you don't wanna repeat code, both queries would call to a generic query using predicates.

choquero70
  • 4,470
  • 2
  • 28
  • 48
0

First of all, Merge classes GetAllOrdersCreatedByUserQuery and GetAllOrdersAcceptedByUserQuery

See following class for reference :

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

And also take view Model for OrderCreatedByUserListViewModel and OrderCreatedByUserListViewModel

See following view model for reference :

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

And finally your MediatR handle method should be like this :

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;
}
Khushali
  • 340
  • 2
  • 8