Spring Data JPA:如何基于嵌入实体实现existsBy查询?
解决Spring Data JPA中嵌入实体字段的existsBy查询问题
错误原因
Spring Data JPA的方法命名规则要求必须对应实体的属性路径。Dentist实体本身没有cpf字段,该字段属于嵌入的Person实体,所以直接写existsByCpf会导致框架找不到对应属性,抛出PropertyReferenceException。
修改步骤
1. 修正Repository接口的方法名
需要按照嵌套属性路径来命名方法,Spring Data支持两种写法:
- 驼峰式:
existsByPersonCpf - 下划线分隔:
existsByPerson_Cpf
修改后的DentistRepository:
@Repository public interface DentistRepository extends JpaRepository<Dentist, UUID> { boolean existsByCroNumber(String croNumber); // 二选一即可 boolean existsByPersonCpf(String cpf); // boolean existsByPerson_Cpf(String cpf); }
2. 修正Service层的调用
让Service方法调用Repository中正确命名的方法:
public boolean existsByCroNumber(String croNumber) { return dentistRepository.existsByCroNumber(croNumber); } public boolean existsByPersonCpf(String cpf) { return dentistRepository.existsByPersonCpf(cpf); } // 如果用下划线版本,对应修改为: // public boolean existsByPerson_Cpf(String cpf) { // return dentistRepository.existsByPerson_Cpf(cpf); // }
3. 修复Controller的参数绑定问题
原Controller方法中同时接收@RequestBody Dentist和Person参数会导致请求体解析错误(请求体只能绑定到一个对象)。应该从传入的dentistDto中直接获取Person的cpf:
@PostMapping public ResponseEntity<Object> saveDentist(@RequestBody @Valid Dentist dentistDto) { if(dentistService.existsByCroNumber(dentistDto.getCroNumber())) { return ResponseEntity.status(HttpStatus.CONFLICT).body("CONFLICT: CRO number is already in use!"); } // 先判断person是否为空,避免空指针 if(dentistDto.getPerson() != null && dentistService.existsByPersonCpf(dentistDto.getPerson().getCpf())) { return ResponseEntity.status(HttpStatus.CONFLICT).body("CONFLICT: CPF number is already in use!"); } var dentistModel = new Dentist(); BeanUtils.copyProperties(dentistDto, dentistModel); dentistModel.setRegistrationDate(LocalDateTime.now(ZoneId.of("UTC"))); return ResponseEntity.status(HttpStatus.CREATED).body(dentistService.save(dentistModel)); }
关键说明
Spring Data JPA的查询方法命名会自动解析属性路径,比如PersonCpf会被解析为dentist.person.cpf,下划线分隔的Person_Cpf效果完全一致,可根据个人习惯选择。
内容的提问来源于stack exchange,提问作者glpsx
相关产品推荐
相关产品推荐

