You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);

方案优势

  1. 完全符合限制条件:不需要修改原有实体,也不用Criteria Builder,纯原生SQL解决关联问题
  2. Spring Data原生支持:直接利用Pageable实现分页和动态排序,无需手动拼接分页/排序SQL
  3. 安全可靠:通过@Param绑定参数,自动避免SQL注入风险
  4. 性能可控:原生SQL可以根据数据库特性优化,比JPA自动生成的SQL更灵活

内容的提问来源于stack exchange,提问作者Sneha Sree Pashikanti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:43:17