Я пытаюсь использовать Generics для создания обработчика запроса на абстрактный запрос на запросы на агрегатные корни в архитектуре дизайна, основанной на домене. QueryResult .
Вы знаете, что я делаю не так?public interface IQuery : IRequest
where T : class
{
Guid CorrelationId { get; }
}
< /code>
public abstract class BaseResult
{
protected BaseResult(ResultStatus status, Dictionary? errors)
{
this.Status = status;
this.Errors = errors ?? new Dictionary();
this.IsSuccess = status == ResultStatus.Success;
}
public bool IsSuccess { get; private set; }
public ResultStatus Status { get; private set; }
public Dictionary Errors { get; private set; }
...
}
< /code>
public class QueryResult : BaseResult
where T : class
{
private QueryResult(T? data, ResultStatus status, Dictionary? errors)
: base(status, errors)
{
this.Data = data;
}
public T? Data { get; }
...
}
< /code>
public class AggregateRootQuery
: IRequest, IQuery
where TAggregate : class, IAggregateRoot // IAggregate root is a marker interface to only allow queries to start at the aggregate root when using my EF core DB context wrapper
where TDto : class
{
public AggregateRootQuery(Guid correlationId)
{
this.CorrelationId = correlationId;
}
public Guid CorrelationId { get; }
}
< /code>
public abstract class BaseAggregateRootQueryHandler : IRequestHandler
where TAggregate : class, IAggregateRoot
where TDto : class
{
protected BaseAggregateRootQueryHandler(IDbContext dbContext, IMapper mapper, ILogger logger)
{
this.DbContext = dbContext;
this.Mapper = mapper;
this.Logger = logger;
}
protected IDbContext DbContext { get; }
protected IMapper Mapper { get; }
protected ILogger Logger { get; }
public async Task Handle(AggregateRootQuery request, CancellationToken cancellationToken)
{
var entities = await this.ApplyFilter(this.DbContext.AggregateRoot())
.ToArrayAsync(cancellationToken);
var dtos = this.MapToDataTransferObjects(entities);
this.Logger.Debug("{Count} {EntityType} read from database", entities.Length, nameof(TAggregate));
return QueryResult.Success(dtos);
}
protected abstract IQueryable ApplyFilter(IQueryable source);
protected virtual IEnumerable MapToDataTransferObjects(IEnumerable source)
{
return this.Mapper.Map(source);
}
}
использование
// Domain.Order implements IAggregateRoot
public class OrderQueryHandler : BaseAggregateRootQueryHandler
{
public OrderQueryHandler(IDbContext dbContext, IMapper mapper, ILogger logger)
:base(dbContext, mapper, logger)
{
}
protected override IQueryable ApplyFilter(IQueryable source)
{
return source.OrderBy(x => x.Name);
{
}
< /code>
var result = await this.Mediator.Send(new AggregateRootQuery(Guid.NewGuid()));
// `IsSuccess` and `Data` have compiler errors because it thinks `result` is an object and not a `QueryResult`
if (!result.IsSuccess || result.Data == null)
{
// Error handing
}
Подробнее здесь: https://stackoverflow.com/questions/752 ... t-handlers