Spring Boot实现未关联实体字段的排序、筛选与分页查询方案
最优解决方案:原生SQL + Spring Data JPA 构造函数投影
既然不能修改实体、不能用Criteria Builder,直接用原生SQL配合Spring Data JPA的@Query注解是最直接高效的方案,既能实现跨表关联,又能利用Spring Data自带的分页、排序和参数绑定能力。
步骤1:定义DTO接收查询结果
因为需要返回Person姓名、Employee ID、Employee姓名三个字段,创建一个简单的DTO类来封装结果(无需JPA实体注解):
public class EmpPersonDTO { private Long employeeId; private String employeeName; private String personName; // 构造方法参数需与SQL查询结果的字段顺序、类型严格匹配 public EmpPersonDTO(Long employeeId, String employeeName, String personName) { this.employeeId = employeeId; this.employeeName = employeeName; this.personName = personName; } // 按需添加getter方法,用于后续业务处理 public Long getEmployeeId() { return employeeId; } public String getEmployeeName() { return employeeName; } public String getPersonName() { return personName; } }
步骤2:在Repository中编写原生SQL查询
在EmployeeRepository接口中添加带原生SQL的查询方法,通过@Query实现关联、筛选、分页和排序:
import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface EmployeeRepository extends JpaRepository<Employee, Long> { @Query( value = "SELECT emp.id AS employeeId, emp.name AS employeeName, p.name AS personName " + "FROM employee emp " + "JOIN person p ON emp.personid = p.id " + "WHERE (:personName IS NULL OR p.name LIKE %:personName%) " + "AND (:employeeName IS NULL OR emp.name LIKE %:employeeName%)", countQuery = "SELECT COUNT(*) " + "FROM employee emp " + "JOIN person p ON emp.personid = p.id " + "WHERE (:personName IS NULL OR p.name LIKE %:personName%) " + "AND (:employeeName IS NULL OR emp.name LIKE %:employeeName%)", nativeQuery = true ) Page<EmpPersonDTO> findEmpPersonList( @Param("personName") String personName, @Param("employeeName") String employeeName, Pageable pageable ); }
步骤3:调用查询实现分页、排序和筛选
通过Pageable对象传递分页和动态排序规则,筛选参数传null即可忽略对应条件:
// 示例1:按Person姓名升序分页,第1页(索引0)每页10条,筛选Person姓名含"张三"的结果 Pageable pageable1 = PageRequest.of(0, 10, Sort.by("personName").asc()); Page<EmpPersonDTO> result1 = employeeRepository.findEmpPersonList("张三", null, pageable1); // 示例2:组合筛选(Person姓名含"李"、Employee姓名含"明"),按Employee姓名降序分页 Pageable pageable2 = PageRequest.of(1, 10, Sort.by("employeeName").desc()); Page<EmpPersonDTO> result2 = employeeRepository.findEmpPersonList("李", "明", pageable2); // 示例3:无筛选,按Employee ID降序分页 Pageable pageable3 = PageRequest.of(0, 15, Sort.by("employeeId").desc()); Page<EmpPersonDTO> result3 = employeeRepository.findEmpPersonList(null, null, pageable3);
方案优势
- 完全符合限制条件:不需要修改原有实体,也不用Criteria Builder,纯原生SQL解决关联问题
- Spring Data原生支持:直接利用
Pageable实现分页和动态排序,无需手动拼接分页/排序SQL - 安全可靠:通过
@Param绑定参数,自动避免SQL注入风险 - 性能可控:原生SQL可以根据数据库特性优化,比JPA自动生成的SQL更灵活
内容的提问来源于stack exchange,提问作者Sneha Sree Pashikanti
相关产品推荐
相关产品推荐

