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.复杂条件多表查询
//需要查询的对象
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 分页+多条件查询 调用示例:
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;即可。
jpa多条件查询重写Specification的toPredicate方法(转)的更多相关文章
- jpa多条件查询
首先继承JpaSpecificationExecutor<T>接口 需要用到JpaSpecificationExecutor<T>中的Page<T> findAll ...
- angularJS 条件查询 品优购条件查询品牌(条件查询和列表展示公用方法解决思路 及 post请求混合参数提交方式)
Brand.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> &l ...
- springboot jpa 多条件查询(多表)
前几天写的,贴上来. 实体类. package com.syl.demo.daomain; import lombok.Data; import javax.persistence.*; /** * ...
- springboot jpa 多条件查询(单表)
需要实现的功能: 多个搜索输入框:全部不填,则查出所有列表:填了条件,就按条件查找:填的条件个数不定. 方法实现的核心:jpa自带的Specification<T> (目前只需要单表,多表 ...
- Spring Boot Jpa 多条件查询+排序+分页
事情有点多,于是快一个月没写东西了,今天补上上次说的. JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将 ...
- spring data jpa 组合条件查询封装
/** * 定义一个查询条件容器 * @author lee * * @param <T> */ public class Criteria<T> implements Spe ...
- spring jpa : 多条件查询
https://www.cnblogs.com/Donnnnnn/p/6277872.html 方式一: 第一步:EmpAccNumService package com.payease.scford ...
- 项目一:第四天 1、快递员的条件分页查询-noSession,条件查询 2、快递员删除(逻辑删除) 3、基于Apache POI实现批量导入区域数据 a)Jquery OCUpload上传文件插件使用 b)Apache POI读取excel文件数据
1. 快递员的条件分页查询-noSession,条件查询 2. 快递员删除(逻辑删除) 3. 基于Apache POI实现批量导入区域数据 a) Jquery OCUpload上传文件插件使用 b) ...
- hbase 利用rowkey设计进行多条件查询
摘要 本文主要内容是通过合理Hbase 行键(rowkey)设计实现快速的多条件查询,所采用的方法将所有要用于查询中的列经过一些处理后存储在rowkey中,查询时通过rowkey进行查询,提高rowk ...
随机推荐
- Medication Reconciliation Overview
http://www.hcsinc.net/HCS-Medication-Reconciliation/med-rec-overview.html At HCS, we've worked with ...
- Lessons learned developing a practical large scale machine learning system
原文:http://googleresearch.blogspot.jp/2010/04/lessons-learned-developing-practical.html Lessons learn ...
- SharePoint 2013网站突然不能登录了。
SharePoint 2013网站突然不能登录了,访问的时候,总是报错: The list has not shared with you. 原因: 原来我不知道什么时候把web applicat ...
- [Backbone]6. Collections.
Define a collection: var AppointmentList = Backbone.Collection.extend({model: Appointment}); RESET t ...
- 【Javascript Demo】遮罩层和弹出层简单实现
最近纠结于遮罩层和弹出层的实现,终于搞定了个简单的版本.示例和代码如下,点击按钮可以看到效果: 1.示例: 2.代码: <!DOCTYPE html PUBLIC "-//W3C//D ...
- 推荐20个很有帮助的web前端开发教程
1. CSS Vocabulary 一个伟大的指向和点击的小应用程序,让你加快速度掌握 CSS 语法的各个不同部分,学习各个属性的正确的名称. 2. Liquidapsive 一个简单的信息化布局,通 ...
- Linux - 系统路径加入命令
系统路径加入命令 本文地址: http://blog.csdn.net/caroline_wendy 1. 在根文件夹建立bin文件夹: $mkdir bin 2. 改动".bash_pro ...
- 【读书笔记】Flickr 网站用户标签的质量控制对策
1.一些背景 标签技术重要意义 标签技术如今已经被广泛应用于包括网络书签.博客.播客.视频分享等在内的多种 Web2. 0 服务 Flickr简介 Flickr 是一集图片存放 交友 组群 邮件等功能 ...
- JavaScript简述一
一.什么时JavaScript JavaScript是一种具有面向对象能力的,解释型的设计语言,更具体一点,它是基于圣明和事件驱动并具有相对安全必的客户端脚本语言,因为它不需要在一个语言环境下运行,只 ...
- 触发器二(DML触发器)(学习笔记)
DML触发器(语句触发器) 由DML语句进行触发,当用户执行了INSERT,UPDATE,DELETE操作时就会触发操作 示例一.只有在每个月的10日才允许办理,新员工入职与离职,其他时间不允许增加和 ...