首页 > 解决方案 > 仅从具有多个过滤条件的数据库中获取选定的列 Spring Boot 2 JPA

问题描述

我正在尝试创建一个 spring boot 2 web 应用程序,它将根据传递给它的过滤条件从数据库中获取数据,但只会获取某些列。

这是我的员工类:

@Entity
@Table("table=emplooyee")
class Employee{ 
         @column("name="fname")
         String fname;
         @column("name="lname")
         String lname;
         @column("name="phoneNo")
         String phoneNo;
         @column("name="address")
         String address;
     }

在我的实体和数据库中还有 25 个这样的字段。

从前端,用户应该能够选择过滤条件,例如:fname、lname、phoneNo、address 等。他可以指定任何组合,例如 fname 和 phoneNo,或 lname 和地址,或者不指定我拥有的任何内容做一个选择 *. 在某种程度上,我想要多个过滤条件。我希望这些过滤器作为来自前端的请求参数。

我的存储库是:

public interface EmployeeRepository extends JpaRepository<Employee,Long>, JpaSpecificationExecutor<Employee>{

}

到目前为止,我已经研究了非常酷的规格。

所以我创建了一个规范,

import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

public class EmployeeSpecs {
    public static Specification<Employee> hasFname(String fname){
        return new Specification<Employee>() {
            @Override
            public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(root.get("fname"),fname);
            }
        };
    }
    public static Specification<Employee> hasLname(String lname){
        return new Specification<Employee>() {
            @Override
            public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(root.get("lname"), lname);
            }
        };
    }
    public static Specification<Employee> hasAddress(String address){
        return new Specification<Employee>() {
            @Override
            public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(root.get("address"), address);
            }
        };
    }
    public static Specification<Employee> hasPhone(String phone){
        return new Specification<Employee>() {
            @Override
            public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(root.get("phone"), phone);
            }
        };
    }
}

现在,根据我的服务,我计划做:

this.employeeRepository.findAll(EmployeeSpecs.hasFName(requestParameterFname).and(EmployeeSpecs.hasLName(requestParameterLname))).forEach(e->list.add(e));

但是,这将获取我的数据库中的所有 25 列。我的前端应用程序有 6 个页面,每个页面都需要显示不同的列,但是这些规范的组合作为 where 子句。

我尝试研究投影的概念,但发现目前 SpringBoot 不支持带有投影的规范。

有没有办法只获取选定的列并具有多个过滤条件?关于能够将传递的请求参数动态附加到我的查询并仅获取相关字段的任何想法?

我是否应该创建单独的实体,以便我只从我的存储库中获取这些字段,然后每次都为每个字段获取一个新规范?这不会创建太多不必要的实体和规范文件吗?

我能想到的另一种方法是,我必须手动提取这些列。这听起来很愚蠢,因为我已经知道我需要做 'select column1, column2, column3 from db where condition1 = true and condition2= true'但我仍在做select *.

任何人都可以指导在这种情况下采取的最佳方法是什么?实现这一目标的最干净的方法是什么?我应该像原生查询一样手动编写查询吗?

简而言之,我想要以下内容:

  1. 多个过滤条件 - 任何可能的组合,即。要传递给我的 sql select 语句的“where”子句的多个条件。
  2. 只有选定的列,而不是全部 - 但不同的用例需要不同的列。

标签: javaspringspring-bootjpaspring-data-jpa

解决方案


Spring Data 没有任何特殊功能或此功能。因此,您需要创建一个自定义方法,在其中将PredicatefromSpecification与选择列表结合起来。

自定义方法可能看起来像这样:

Employee findBySpecAndColumns(Specification spec, List<String> columns) {
    
    // create select list as described here, but from the list of columns or whatever you use to specify which columns you want to select: https://www.objectdb.com/java/jpa/query/jpql/select#SELECT_in_Criteria_Queries

    // use spec.toPredicate(...) to create the where clause

    // execute the query.

    // transform the result to the form you need/want.
}

另请参阅:如何使用 Criteria API 指定选择列表

不过,我想知道这是否值得付出努力。我希望为数据选择 25 列以显示在单个页面上可能与从同一个表中选择 4 列没有太大区别。


推荐阅读