【发布时间】:2020-03-05 19:47:11
【问题描述】:
我正在使用 CQRS 和 MediatR 库,试图学习一些最佳实践。 我遇到的一个问题是命令/查询处理程序中的代码重复。我想知道在处理程序之间共享逻辑的最佳方式是什么。
示例: 我有一个定义 ID 属性的抽象实体类。所有实体都继承自该类。
public abstract class Entity
{
public long Id { get; private set; }
protected Entity(long id)
{
Id = id;
}
...
}
然后对于每个实体,我想创建一个 GetById 查询。其中一个查询如下所示:
public class GetUserByIdQuery : IRequest<UserDto>
{
public long UserId { get; set; }
public class Handler : IRequestHandler<GetUserByIdQuery, UserDto>
{
private readonly IRepository<User> repository;
private readonly IMapper mapper;
public Handler(IUnitOfWork unitOfWork, IMapper mapper)
{
repository = unitOfWork.GetRepository<User>();
this.mapper = mapper;
}
public async Task<UserDto> Handle(GetUserByIdQuery request, CancellationToken cancellationToken)
{
var user = await repository.FindAsync(request.UserId, null, cancellationToken);
if (user is null)
{
throw new EntityNotFoundException();
}
return mapper.Map<UserDto>(user);
}
}
}
问题是这个类对于所有实体看起来都完全相同。如果没有 CQRS,我可能会有这样的事情:
public class EntityFinder<TEntity, TDto> where TEntity : Entity
{
private readonly IRepository<TEntity> repository;
private readonly IMapper mapper;
public EntityFinder(IUnitOfWork unitOfWork, IMapper mapper)
{
repository = unitOfWork.GetRepository<TEntity>();
this.mapper = mapper;
}
public async Task<TDto> GetByIdAsync(long id)
{
var entity = await repository.FindAsync(id);
if (entity is null)
{
throw new EntityNotFoundException();
}
return mapper.Map<TDto>(entity);
}
}
我尝试使用通用查询和处理程序执行类似的操作,但 MediatR 无法找到处理程序(即使我尝试将其手动注册到 DI 容器)。
避免这种重复的最佳方法是什么?
【问题讨论】:
-
我最近也一直在研究 Mediatr,我一直在尝试适应的一件事是代码重复的感觉。查看 Jimmy Bogard(库维护者)所做的一些谈话,他似乎在一定程度上认为这是一种好处,因为这意味着当对命令或查询进行更改时,只有一个实例被更改,没有风险其他。例如,它还允许您拥有不同的输入和输出 DTO。期待看到其他有更多经验的人怎么说。
-
另外,请参阅 Jimmy 关于此主题的一些注释here
-
@TylerHundley,我必须不同意这一点。假设我们有 100 个这样的查询。我想扩展它,在加载数据时添加日志记录。现在,我将花费更多时间在任何地方复制/粘贴代码。然后需要花费大量时间来测试所有查询。所以对我来说,重复的代码使扩展变得更加困难,根本没有好处。
-
@Alex-TinLe 公平点。我认为,在可能的情况下,应该通过 Mediatr 本身通过 Behaviors 来处理诸如日志记录之类的横切关注点。我认为减少重复总体上是一个很好的目标,尽管询问代码是否真正重复(它们总是完全相互镜像)或者它现在是否只是相同(即,而不是使用一个 DTO 进行输入和输出) ,为每个使用不同的 DTO,因为将来可能会改变一个)。我认为 Jimmy 在我之前评论中分享的文章中给出了一些好的想法。
标签: c# oop domain-driven-design cqrs mediatr