【问题标题】:How to combine OData 4 and Automapper in .NET Core 3.1如何在 .NET Core 3.1 中结合 OData 4 和 Automapper
【发布时间】:2020-10-03 19:13:13
【问题描述】:

我尝试在 .NET Core 3.1 中结合 Automapper 和 OData,但我已经卡住了一段时间。我的 OData 控制器以这种方式工作就像一个魅力:

[ODataRoute]
[EnableQuery]
public IQueryable<Unit> Get()
{
    return _context.Units;
}

_context 是我的 EF DbContext

但是,我需要公开 UnitDto 而不是 Unit

到目前为止我尝试的是:

[ODataRoute]
[EnableQuery]
public IQueryable<UnitDto> Get()
{
    var units = _context.Units;
    return units.ProjectTo<UnitDto>(_mapper.ConfigurationProvider);
}

但这会导致空引用异常:

System.NullReferenceException:对象引用未设置为对象的实例。

在 lambda_method(Closure , QueryContext , DbDataReader , ResultContext , Int32[] , ResultCoordinator)
在 Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.AsyncEnumerator.MoveNextAsync() at Microsoft.AspNetCore.Mvc.Infrastructure.AsyncEnumerableReader.ReadInternal[T](Object value) at Microsoft.AspNetCore.Mvc.Infrastructure.AsyncEnumerableReader.ReadInternal[T](Object value) at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsyncEnumerable(ActionContext context, ObjectResult result, Object asyncEnumerable, Func2 读者)
等等

使用Automapper.Aspnetcore.Odata.EFCore 中的GetQueryAsync 会导致相同的异常:

[HttpGet]
public async Task<IActionResult> GetAll(ODataQueryOptions<UnitDto> options)
{
    return Ok(await _context.Units.GetQueryAsync(_mapper, options));
}

关于如何实现这一目标的任何想法?这是要走的路吗?我做错了什么还是应该走另一个方向?

【问题讨论】:

    标签: .net-core odata automapper


    【解决方案1】:

    最后我找到了解决方法。因此,假设更多人有这个问题,我就是这样做的。

    第一件事是对数据库对象执行查询。然后得到它们的结果(使用JSON(反)序列化,不知道更好的方法)并将它们映射到DTO对象。

    [ODataRoute]
    [EnableCustomQuery]
    public IEnumerable<UnitDto> Get(ODataQueryOptions<Unit> opts)
    {
           var queryResult = opts.ApplyTo(_context.Units);
    
           var units = _mapper.Map<List<Unit>>(JsonConvert.DeserializeObject<List<UnitOData>>(JsonConvert.SerializeObject(queryResult)));
    
           return _mapper.Map<List<UnitDto>>(units);
     }
    

    问题是我想使用所有查询选项,包括 $expand$filter$skip$top$count。但是查询应该在数据库对象上,而在 DTO 对象上查询。因此,我将它链接到我的 EDM 模型中,如下所示:

    var unitsConfig = builder.EntitySet<Unit>("UnitsWithoutDto");
    unitsConfig.EntityType.Property(p => p.InternalReference).Name = "ExternalReference";
    

    反序列化的结果现在将是数据库对象,当过滤特定属性时,该对象的一个​​属性发生了变化。因此我创建了一个新的UnitOData

    public class UnitOData : Unit
    {
        public string DisplayName { get; set; }
    }
    

    并根据特定属性是否存在将其映射到原始对象。

    CreateMap<UnitOData, Unit>()
         .ForMember(a => a.InternalReference, opt => opt.MapFrom(src => src.ExternalReference ?? src.InternalReference));
    

    然后一切正常,期待分页。因此,a 创建了一个忽略 $skip$top 查询选项的自定义过滤器。

    public class EnableCustomQueryAttribute : EnableQueryAttribute
    {
        public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
        {
            var ignoreQueryOptions = AllowedQueryOptions.Skip | AllowedQueryOptions.Top;
            return queryOptions.ApplyTo(queryable, ignoreQueryOptions);
        }
    }
    

    如果有真正的解决方案,请分享。

    【讨论】:

      猜你喜欢
      • 2022-01-18
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-10
      • 2020-07-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多