jpa多条件查询重写Specification的toPredicate方法(转)

Spring Data JPA支持JPA2.0的Criteria查询,相应的接口是JpaSpecificationExecutor。Criteria 查询:是一种类型安全和更面向对象的查询 。

这个接口基本是围绕着Specification接口来定义的, Specification接口中只定义了如下一个方法:

Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);

要理解这个方法,以及正确的使用它,就需要对JPA2.0的Criteria查询有一个足够的熟悉和理解,因为这个方法的参数和返回值都是JPA标准里面定义的对象。

Criteria查询基本概念

Criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。

CriteriaQuery接口:代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用 
Root接口:代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似

1:Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型。

2:查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得。

3:Criteria查询,可以有多个查询根。

4:AbstractQuery是CriteriaQuery 接口的父类,它提供得到查询根的方法。CriteriaBuilder接口:用来构建CritiaQuery的构建器对象Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合。

Criteria查询基本对象的构建

1:通过EntityManager的getCriteriaBuilder或EntityManagerFactory的getCriteriaBuilder方法可以得到CriteriaBuilder对象2:通过调用CriteriaBuilder的createQuery或createTupleQuery方法可以获得CriteriaQuery的实例

3:通过调用CriteriaQuery的from方法可以获得Root实例过滤条件

A:过滤条件会被应用到SQL语句的FROM子句中。在criteria 查询中,查询条件通过Predicate或Expression实例应用到CriteriaQuery对象上。

B:这些条件使用 CriteriaQuery .where 方法应用到CriteriaQuery 对象上

C:CriteriaBuilder也作为Predicate实例的工厂,通过调用CriteriaBuilder 的条件
方( equalnotEqual, gt, ge,lt, le,between,like等)创建Predicate对象。

D:复合的Predicate 语句可以使用CriteriaBuilder的and, or andnot 方法构建。 

    构建简单的Predicate示例:

            Predicate p1=cb.like(root.get(“name”).as(String.class), “%”+uqm.getName()+“%”);

            Predicate p2=cb.equal(root.get("uuid").as(Integer.class), uqm.getUuid());

            Predicate p3=cb.gt(root.get("age").as(Integer.class), uqm.getAge());

        构建组合的Predicate示例:

           Predicate p = cb.and(p3,cb.or(p1,p2));

下面我们用两个示例代码来更深入的了解:

1.复杂条件多表查询

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

//需要查询的对象

public class Qfjbxxdz {

    @Id

    @GeneratedValue(generator = "system-uuid")

    @GenericGenerator(name = "system-uuid", strategy = "uuid.hex")

    private String id;

    @OneToOne

    @JoinColumn(name = "qfjbxx")

    private Qfjbxx qfjbxx; //关联表

    private String fzcc;

    private String fzccName;

    @ManyToOne

    @JoinColumn(name = "criminalInfo")

    private CriminalInfo criminalInfo;//关联表

    @Column(length=800)

    private String bz;

    //get/set......

}

//创建构造Specification的方法

//这里我传入两个条件参数因为与前段框架有关,你们写的时候具体自己业务自行决断

private Specification<Qfjbxxdz> getWhereClause(final JSONArray condetion,final JSONArray search) {

        return new Specification<Qfjbxxdz>() {

            @Override

            public Predicate toPredicate(Root<Qfjbxxdz> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

                List<Predicate> predicate = new ArrayList<>();

                Iterator<JSONObject> iterator = condetion.iterator();

                Predicate preP = null;

                while(iterator.hasNext()){

                    JSONObject jsonObject = iterator.next();

                    //注意:这里用的root.join 因为我们要用qfjbxx对象里的字段作为条件就必须这样做join方法有很多重载,使用的时候可以多根据自己业务决断

                    Predicate p1 = cb.equal(root.join("qfjbxx").get("id").as(String.class),jsonObject.get("fzId").toString());

                    Predicate p2 = cb.equal(root.get("fzcc").as(String.class),jsonObject.get("ccId").toString());

                    if(preP!=null){

                        preP = cb.or(preP,cb.and(p1,p2));

                    }else{

                        preP = cb.and(p1,p2);

                    }

                }

                JSONObject jsonSearch=(JSONObject) search.get(0);

                Predicate p3=null;

                if(null!=jsonSearch.get("xm")&&jsonSearch.get("xm").toString().length()>0){

                   p3=cb.like(root.join("criminalInfo").get("xm").as(String.class),"%"+jsonSearch.get("xm").toString()+"%");

                }

                Predicate p4=null;

                if(null!=jsonSearch.get("fzmc")&&jsonSearch.get("fzmc").toString().length()>0){

                    p4=cb.like(root.join("qfjbxx").get("fzmc").as(String.class),"%"+jsonSearch.get("fzmc").toString()+"%");

                }

                Predicate preA;

                if(null!=p3&&null!=p4){

                    Predicate  preS =cb.and(p3,p4);

                    preA =cb.and(preP,preS);

                }else if(null==p3&&null!=p4){

                    preA=cb.and(preP,p4);

                }else if(null!=p3&&null==p4){

                    preA=cb.and(preP,p3);

                }else{

                    preA=preP;

                }

                predicate.add(preA);

                Predicate[] pre = new Predicate[predicate.size()];

                query.where(predicate.toArray(pre));

                return query.getRestriction();

            }

编写DAO类或接口 
dao类/接口 需继承

public interface JpaSpecificationExecutor<T>

接口; 
如果需要分页,还可继承

public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID>

JpaSpecificationExecutor 接口具有方法

Page<T> findAll(Specification<T> spec, Pageable pageable); //分页按条件查询

List<T> findAll(Specification<T> spec); //不分页按条件查询

方法。 我们可以在Service层调用这两个方法。 
两个方法都具有 Specification spec 参数,用于设定查询条件。 
Service 分页+多条件查询 调用示例:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

studentInfoDao.findAll(new Specification<StudentInfo> () { 

   public Predicate toPredicate(Root<StudentInfo> root, 

     CriteriaQuery<?> query, CriteriaBuilder cb) { 

    Path<String> namePath = root.get("name"); 

    Path<String> nicknamePath = root.get("nickname"); 

    /**

         * 连接查询条件, 不定参数,可以连接0..N个查询条件

         */

    query.where(cb.like(namePath, "%李%"), cb.like(nicknamePath, "%王%")); //这里可以设置任意条查询条件 

    return null

   

  }, page); 

 

  这里通过CriteriaBuilder 的like方法创建了两个查询条件, 姓名(name)字段必须包含“李”, 昵称(nickname)字段必须包含“王”。 
然后通过 
连接多个查询条件即可。 这种方式使用JPA的API设置了查询条件,所以不需要再返回查询条件Predicate给Spring Data Jpa,故最后return null;即可。

原文地址:https://www.cnblogs.com/morganlin/p/12000165.html

时间: 2024-10-12 18:18:14

jpa多条件查询重写Specification的toPredicate方法(转)的相关文章

Spring data jpa @OneToMany 在一的一端进行查询()对集合属性设置条件查询)

业务场景: 一个商品对应多个仓存,需要查询商品在某个或某几个库存中存在时,查询出来. 实体类 ,商品Goods @Entity @Table(name = "es_goods") public class Goods { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "goods_id") private Integer id; private String name; //

hbase 利用rowkey设计进行多条件查询

摘要 本文主要内容是通过合理Hbase 行键(rowkey)设计实现快速的多条件查询,所采用的方法将所有要用于查询中的列经过一些处理后存储在rowkey中,查询时通过rowkey进行查询,提高rowkey的利用率,加快查询速度.行键(rowkey)并不是简单的把所有要查询的列的值直接拼接起来,而是将各个列的数据转成整型(int)数据来存储.之后实现两个自定义的比较器(comparator):一个是相等比较器,用于实现类似于SQL的多条件精确查找功能. select * from table wh

jpa自定义条件分页查询

主要依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> 这里以我最近自己瞎折腾的项目部分代码为例子(仅展示主要部分): 实体类名称(Confusion) 需要注意的是 类上+ @Entity 主键字段+ @Id package cn.

jpa使用自定义查询条件

涛sir:http://www.cnblogs.com/it-taosir/p/9874033.html 意思就是jpa中使用类似like(模糊查询)和 limit (分页)查询结合,通过以下例子解析: 可理解为like,实际效率是比模糊查询like效率高的 建表:sql create table order_info ( order_id varchar(30) not null, source_id varchar(30), serial_no varchar(30), source_sys

【Spring Data 系列学习】Spring Data JPA 自定义查询,分页,排序,条件查询

Spring Boot Jpa 默认提供 CURD 的方法等方法,在日常中往往时无法满足我们业务的要求,本章节通过自定义简单查询案例进行讲解. 快速上手 项目中的pom.xml.application.properties与 Chapter1 相同 实体类映射数据库表 user 实体类 @Entity public class User implements Serializable { private static final long serialVersionUID = -39076354

【JPA】表达条件查询的关键字

1.通过解析方法名创建查询 框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find.findBy.read.readBy.get.getBy,然后对剩下部分进行解析.并且如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询. 在创建查询时,我们通过在方法名中使用属性名称来表达,比如 findByUserAddressZip ().框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析,详细规则如下(此处假

Spring Data JPA 条件查询的关键字

Spring Data JPA 为此提供了一些表达条件查询的关键字,大致如下: And --- 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd): Or --- 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr): Between --- 等价于 SQL 中的 between 关键字,比如 findBySala

Hibernate结合JPA编写通用泛型多条件查询

项目中使用Hibernate和JPA对数据库对象进行实例化,但是生成的方法不支持多条件查询.而如果针对每一个数据库对象进行多条件查询编码,则会变得很麻烦,而且一旦以后发生表结构发生变化,这些方法可能还需要进行重新编码.所以考虑编写一个方法可以对数据库对象进行多条件查询,并返回泛型对象,这样就可以方便使用.具体实现思路如下: 第一步:编写数据库查询参数对象,此部分包含两个,一个是查询实体名称(QueryCondition.java),一个是数据库查询条件对象(QueryParameter.java

Spring Data Jpa之高级查询(jpa-spec插件)

友情链接:Spring Data Jpa的动态查询库 https://github.com/wenhao/jpa-spec 功能介绍 兼容Spring Data Jpa 和JPA2.1接口. Equal/NotEqual/Like/NotLike/In/NotIn支持可变参数, Equal/NotEqual 支持空(Null)值. 每个条件支持关联查询. 支持自定义条件查询. 条件构建器. 支持分页和排序. 导包: <dependency> <groupId>com.github.