A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

 
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>  

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马