Orika设置mapNulls(false)仍映射空值,如何保留JPA实体ID?
我之前也碰到过类似的坑,Orika的mapNulls(false)在源对象没有对应字段的场景下,有时候并不会像我们预期的那样保留目标对象的原有值。针对你的问题,这里有几个实用的解决思路:
1. 显式排除实体的ID字段
你的配置里用了byDefault(),它会自动匹配所有同名字段——哪怕DTO里没有ID字段,Orika还是会尝试处理实体的ID属性。这时候因为DTO里没有对应的ID值,会被视为null,进而覆盖实体原有的ID(即使你设置了mapNulls(false),这种场景下可能不生效)。
解决办法很直接,在classMap里显式排除实体的ID字段,让Orika完全不处理它:
@Bean public MapperFactory roadAssisanceMapperFactory() { MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); mapperFactory.classMap(RoadAssistance.class, RoadAssistanceDto.class) .mapNulls(false).mapNullsInReverse(false) .exclude("city").exclude("country").exclude("region").exclude("images") .exclude("id") // 新增这行,替换为你实体实际的ID字段名 .byDefault().register(); return mapperFactory; }
把"id"换成你实体中真实的ID字段名称(比如"roadAssistanceId"),这样Orika在映射时会完全跳过ID字段,实体原有的ID值就会被保留下来。
2. 手动指定需要映射的字段(替代byDefault)
如果你想更精确地控制映射逻辑,避免byDefault()带来的意外,可以放弃自动匹配,手动列出所有需要映射的字段:
@Bean public MapperFactory roadAssisanceMapperFactory() { MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); mapperFactory.classMap(RoadAssistance.class, RoadAssistanceDto.class) .mapNulls(false).mapNullsInReverse(false) // 只映射你需要的字段,示例如下: .field("serviceName", "serviceName") .field("assistanceType", "assistanceType") .field("contactPhone", "contactPhone") // 继续添加其他需要映射的字段,不包含ID和已排除的城市、国家等 .register(); return mapperFactory; }
这种方式虽然繁琐,但能彻底避免Orika处理到ID字段,确保原有值不会被覆盖。
3. 版本特性检查(可选)
你使用的Orika 1.5.2版本相对较老,可能在mapNulls的处理逻辑上和新版本有差异。如果上面的方法都不生效,可以尝试升级到较新的稳定版本(比如1.5.4),不过升级前要注意项目的兼容性问题。
修改完配置后测试一下,调用roadAssisanceMapperFactory().getMapperFacade().map(roadAssistanceDto, roadAssistance)时,实体的ID应该就能正常保留了。
内容的提问来源于stack exchange,提问作者ROZZ

