Spring Data JPA Pageable排序错误选用子查询别名,如何指定正确别名
问题原因
这是Hibernate处理带自定义JPQL的分页排序时的别名匹配优先级问题:当你传入带主表别名的排序字段t.id时,Hibernate会优先匹配查询语句中子查询的同名字段所属别名,这里子查询的a别名先被匹配到,就生成了错误的order by a.id语句。
解决方法
方法1:排序字段用返回DTO的属性名(最推荐)
你构造EmployeeDTO时第一个入参是id,对应DTO的id属性,直接把排序字段从t.id改成id即可。Spring Data JPA会自动映射到select子句中对应的返回字段,不会触发别名匹配混乱的问题。
修改服务层代码:
public Page<EmployeeDTO> findEmployee(EmployeeExample employeeExample) { EmployeeDTO employeeDTO = employeeExample.getExample(); return employeeRepository.find( PageRequest.of(employeeExample.getPage(), employeeExample.getSize(), employeeExample.getSortDirection() == SortDirection.DESC ? Sort.Direction.DESC : Sort.Direction.ASC, // 改为DTO对应的属性名,不需要加表别名 "id" )); }
方法2:给查询字段加显式别名,排序用别名
如果方法1不生效(比如DTO字段和查询字段名不匹配),可以在JPQL的select子句给需要排序的字段加自定义别名,排序时用这个自定义别名即可。
先修改Repository的@Query:
@Query(value = // 给主表id加显式别名 emp_id " select new com.my.EmployeeDTO(t.id as emp_id, " + " t.fullName, " + " t.nationalCode, " + " (select a.unit.code from UnitEmployee a where a.employee.id = t.id and a.isDefault = true)) " + " from Employee t ", countQuery = "select count(t.id) " + " from Employee t ") Page<EmployeeDTO> find(Pageable page);
再把服务层排序字段改为emp_id即可。
方法3:把排序逻辑直接写入JPQL(适合固定排序场景)
如果你的排序规则是固定不需要动态传参的,直接把order by写在JPQL里,就不会触发自动拼接排序的bug:
@Query(value = " select new com.my.EmployeeDTO(t.id, " + " t.fullName, " + " t.nationalCode, " + " (select a.unit.code from UnitEmployee a where a.employee.id = t.id and a.isDefault = true)) " + // 直接写死排序规则 " from Employee t order by t.id desc ", countQuery = "select count(t.id) " + " from Employee t ") Page<EmployeeDTO> find(Pageable page);
内容的提问来源于stack exchange,提问作者Rasool Ghafari
相关产品推荐
相关产品推荐

