DDD、CQRS 和 Mediatr 查询过滤
DDD, CQRS and Mediatr query filtering
我正在做一个遵循 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 时,所有代码实际上是相同的。
唯一的例外是我在 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 个查询同时执行这两种操作在客观上更好?
编辑:添加了更好的标签
查询可以保持独立(因此它们遵循 SOLID)并且您可以通过其他方式避免代码重复。也许尝试提取查询的重复部分以获取订单,而不是首先在 virtual
方法中使用 where
过滤它们,然后在各自的查询中过滤它们。
首先,合并classes GetAllOrdersCreatedByUserQuery
和GetAllOrdersAcceptedByUserQuery
参考以下class:
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;
}
您可以将规范模式应用于查询,即一个以谓词作为参数的查询。
但是 DDD 提倡使用一种无处不在的语言,如果你的用户不使用谓词说话,而是使用具体的方法名称,我会向用户提供 2 个查询,然后如果你不想重复代码,两个查询都将使用谓词调用通用查询。
我正在做一个遵循 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 时,所有代码实际上是相同的。
唯一的例外是我在 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 个查询同时执行这两种操作在客观上更好?
编辑:添加了更好的标签
查询可以保持独立(因此它们遵循 SOLID)并且您可以通过其他方式避免代码重复。也许尝试提取查询的重复部分以获取订单,而不是首先在 virtual
方法中使用 where
过滤它们,然后在各自的查询中过滤它们。
首先,合并classes GetAllOrdersCreatedByUserQuery
和GetAllOrdersAcceptedByUserQuery
参考以下class:
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;
}
您可以将规范模式应用于查询,即一个以谓词作为参数的查询。
但是 DDD 提倡使用一种无处不在的语言,如果你的用户不使用谓词说话,而是使用具体的方法名称,我会向用户提供 2 个查询,然后如果你不想重复代码,两个查询都将使用谓词调用通用查询。