ModelMapper映射DTO与实体时location_id为空触发非空约束报错如何解决?
问题根因
Person实体的location字段是Location实体类型,而PersonDTO的location字段是Long类型的主键ID,ModelMapper默认没有对应类型转换规则,导致映射后Person的location属性为null,触发数据库location_id字段非空约束报错。
解决方案
方案1:注册全局类型转换器(推荐,可复用)
自定义Long转Location的转换器并注册到ModelMapper,所有涉及该类型转换的场景都可以复用:
// 首先在Service中注入LocationRepository @Autowired private LocationRepository locationRepository; // 项目启动时注册转换器(可放在ModelMapper配置类或当前Service的初始化方法中) @PostConstruct public void initModelMapper() { Converter<Long, Location> longToLocationConverter = context -> { Long locationId = context.getSource(); if (locationId == null) { return null; } // 可根据业务需求调整不存在时的处理逻辑 return locationRepository.findById(locationId) .orElseThrow(() -> new RuntimeException("关联Location不存在,ID:" + locationId)); }; modelMapper.addConverter(longToLocationConverter); }
配置完成后原有转换逻辑无需修改即可正常映射。
方案2:手动补全关联属性(简单直接,适合单场景使用)
无需全局配置,直接在转换方法中手动查询并赋值location属性:
// 首先在Service中注入LocationRepository @Autowired private LocationRepository locationRepository; private Person convertToPerson2(PersonDTO personDTO) { modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.LOOSE); Person person = modelMapper.map(personDTO, Person.class); // 手动设置location属性 if (personDTO.getLocation() != null) { Location location = locationRepository.findById(personDTO.getLocation()) .orElseThrow(() -> new RuntimeException("关联Location不存在,ID:" + personDTO.getLocation())); person.setLocation(location); } return person; }
方案3:调整DTO结构实现隐式映射(无需额外查库)
修改DTO结构匹配实体层级,ModelMapper可自动映射ID属性,Hibernate会直接关联已存在的Location记录:
@Data public class PersonDTO { private String username; private String firstName; private String lastName; // 调整为嵌套结构匹配实体层级 private LocationIdDTO location; @Data public static class LocationIdDTO { private Long id; } }
对应请求参数调整为:
{ "username":"bulbul", "firstName":"Bulbul", "lastName":"Ahmed", "location":{ "id":1 } }
内容的提问来源于stack exchange,提问作者Bulbul Ahmed
相关产品推荐
相关产品推荐

