如何在.NET Core 3.1中结合OData 4和Automapper

如何解决如何在.NET Core 3.1中结合OData 4和Automapper

我尝试在.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.QueryingEnumerable 1.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,Func 2阅读器处)

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

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

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

解决方法

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

第一件事是对数据库对象执行查询。然后获取它们的结果(使用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));

然后一切正常,请期待分页。因此,创建了一个自定义过滤器,该过滤器将忽略$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);
    }
}

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-