EF Core对接PostgreSQL JSONB列时Automapper ProjectTo报错如何解决?
报错原因
你自定义了TestInfo类型到PostgreSQL jsonb类型的序列化值转换器,EF Core无法解析AutoMapper生成的访问Info内部属性(Tags/Counts/InfoName)的表达式,会尝试直接将数据库返回的jsonb字符串强制转换为对应数组/字符串类型,因此抛出类型转换异常。你贴的手动Select可以正常运行是因为你没有映射数组类型的字段,如果手动在Select中增加Tags = s.Info.Tags配置,也会出现同类报错。
最优解决方案(支持投影查询)
使用Npgsql官方提供的JSON序列化映射支持,替换自定义值转换器,EF Core即可正确识别jsonb字段内部属性的访问表达式,自动翻译成PostgreSQL原生jsonb查询语法,适配AutoMapper的ProjectTo逻辑。
步骤如下:
- 安装对应NuGet包:
- 如果你习惯用Newtonsoft.Json:安装
Npgsql.EntityFrameworkCore.PostgreSQL.NewtonsoftJson,版本和你当前使用的Npgsql EF Core驱动版本保持一致 - 如果你习惯用System.Text.Json:安装
Npgsql.EntityFrameworkCore.PostgreSQL.Json,版本和驱动保持一致
- 如果你习惯用Newtonsoft.Json:安装
- 修改DbContext注册配置,开启JSON序列化支持:
services.AddDbContext<你的DbContext类名>(opt => opt.UseNpgsql("你的数据库连接字符串", o => { // 用Newtonsoft.Json就选这个 o.UseNewtonsoftJson(); // 用System.Text.Json就选这个 // o.UseJson(); }) ); - 删除
TestConfig中自定义的HasConversion配置,修改后配置如下:public override void Configure(EntityTypeBuilder<Test> builder) { builder.HasKey(m => m.Id); builder.Property(s => s.Info) .HasColumnType("jsonb"); builder.HasIndex(s => s.Info) .HasMethod("gin") .HasOperators("jsonb_ops"); }
修改完成后你的原有ProjectTo代码就可以正常运行了。
临时兼容方案
如果你不想修改现有值转换器,可以先将符合条件的实体加载到内存后再执行映射,缺点是会加载Test实体的全部字段,性能略低于投影查询:
[HttpGet] [Route("/test/{id}")] public async Task<IActionResult> GetTest([FromRoute (Name = "id")][Required]string id) { var entities = await _context.Tests.Where(s => s.Id == id).ToListAsync(); var dtoList = _mapper.Map<List<TestDTO>>(entities); return Ok(dtoList); }
内容的提问来源于stack exchange,提问作者VietNg
相关产品推荐
相关产品推荐

