Spring Data JPA中的动态查询实例
spring data jpa大大的简化了我们持久层的开发,但是实际应用中,我们还是需要动态查询的。
比如,前端有多个条件,这些条件很多都是可选的,那么后端的sql,就应该是可以定制的,在使用hibernate的时候,可以通过判断条件来拼接sql(hql),当然,spring data jpa在简化我们开发的同时,也是提供了支持的。
通过实现criteria二实现的动态查询,需要我们的repo接口继承jpaspecificationexecutor接口,这是个泛型接口。
然后查询的时候,传入动态查询参数,分页参数等即可。
使用起来很简单,不过为了知其所以然,先介绍一下criteria api。
criteria api
如果编译器能够对查询执行语法正确性检查,那么对于 java 对象而言该查询就是类型安全的。java™persistence api (jpa) 的 2.0 版本引入了 criteria api,这个 api 首次将类型安全查询引入到 java 应用程序中,并为在运行时动态地构造查询提供一种机制。本文介绍如何使用 criteria api 和与之密切相关的 metamodel api 编写动态的类型安全查询。
在使用spring data jpa的时候,只要我们的repo层继承jpaspecificationexecutor接口就可以使用specification进行动态查询了,我们先看下jpaspecificationexecutor接口:
public interface jpaspecificationexecutor<t> { t findone(specification<t> spec); list<t> findall(specification<t> spec); page<t> findall(specification<t> spec, pageable pageable); list<t> findall(specification<t> spec, sort sort); long count(specification<t> spec); }
可以看到提供了5个方法,方法的参数和返回值已经很明显的表达了其意图。其中的参数,pageable和sort应该是比较简单的,分别是分页参数和排序参数,而重点就是specification参数,先看下这个接口的定义:
public interface specification<t> { predicate topredicate(root<t> root, criteriaquery<?> query, criteriabuilder cb); }
其中就一个方法,返回的是动态查询的数据结构。
javax.persistence.criteria.predicate topredicate(javax.persistence.criteria.root<t> root, javax.persistence.criteria.criteriaquery<?> query, javax.persistence.criteria.criteriabuilder cb);
这里使用的都是java ee中的规范,具体实现本人采用的是hibernate,当然也可以选择其他实现了jpa规范的数据持久层框架。
这里需要再次回过头看看criteria api中的一些东西:
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:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合
其中支持的方法非常之强大,下面给出一个示例,大家可以参考一下,同样的,可以根据示例,自己可以写出更为复杂的查询:
repo接口:
public interface devhrempconstrastdao extends jparepository<devhrempconstrast, long>,jpaspecificationexecutor<devhrempconstrast>
查询实例1:
/** * 条件查询时动态组装条件 */ private specification<devhrempconstrast> where( final string corg,final string name,final string type,final string date,final string checker){ return new specification<devhrempconstrast>() { @override public predicate topredicate(root<devhrempconstrast> root, criteriaquery<?> query, criteriabuilder cb) { list<predicate> predicates = new arraylist<predicate>(); //机构 if(corg!=null&&!corg.equals("")){ list<string> orgids = organizationdao.findbyname("%"+corg+"%"); if(orgids.size()>0&&orgids.size()<1000) predicates.add(root.<string>get("confirmorgno").in(orgids));//confirmorgno } //名字 if(name!=null&&!name.equals("")){ list<string> userids = userdao.findbyname(name); if(userids.size()>0&&userids.size()<1000)//如果太多就不管了这个条件了 predicates.add(root.<string>get("hrusername").in(userids)); } //类型 if(type!=null&&!type.equals("")) predicates.add(cb.equal(root.<string>get("hrupdatetype"),type)); //日期 if(date!=null&&!date.equals("")){ //处理时间 simpledateformat format = new simpledateformat("yyyy-mm-dd"); date startdate; date enddate; try { startdate = format.parse(date); } catch (parseexception e) { startdate = new date(946656000000l);//2000 01 01 } enddate = startdate; calendar calendar = calendar.getinstance() ; calendar.settime(enddate); calendar.add(calendar.date, 1); enddate = calendar.gettime(); calendar = null; predicates.add(cb.between(root.<date>get("insdate"),startdate,enddate)); } //审核人 if(checker!=null&&!checker.equals("")){ list<string> userids = userdao.findbyname(checker); if(userids.size()>0&&userids.size()<1000)//如果太多就不管了这个条件了 predicates.add(root.<string>get("confirmuserid").in(userids)); } return query.where(predicates.toarray(new predicate[predicates.size()])).getrestriction(); } }; }
查询实例2:
/** * 条件查询时动态组装条件 */ private specification<devhrempconstrast> where( final string corg,final string name,final string type,final string date,final string checker){ return new specification<devhrempconstrast>() { @override public predicate topredicate(root<devhrempconstrast> root, criteriaquery<?> query, criteriabuilder cb) { list<predicate> predicates = new arraylist<predicate>(); //机构 if(corg!=null&&!corg.equals("")){ list<string> orgids = organizationdao.findbyname("%"+corg+"%"); if(orgids.size()>0&&orgids.size()<1000) predicates.add(root.<string>get("confirmorgno").in(orgids));//confirmorgno } //名字 if(name!=null&&!name.equals("")){ list<string> userids = userdao.findbyname(name); if(userids.size()>0&&userids.size()<1000)//如果太多就不管了这个条件了 predicates.add(root.<string>get("hrusername").in(userids)); } //类型 if(type!=null&&!type.equals("")) predicates.add(cb.equal(root.<string>get("hrupdatetype"),type)); //日期 if(date!=null&&!date.equals("")){ //处理时间 simpledateformat format = new simpledateformat("yyyy-mm-dd"); date startdate; date enddate; try { startdate = format.parse(date); } catch (parseexception e) { startdate = new date(946656000000l);//2000 01 01 } enddate = startdate; calendar calendar = calendar.getinstance() ; calendar.settime(enddate); calendar.add(calendar.date, 1); enddate = calendar.gettime(); calendar = null; predicates.add(cb.between(root.<date>get("insdate"),startdate,enddate)); } //审核人 if(checker!=null&&!checker.equals("")){ list<string> userids = userdao.findbyname(checker); if(userids.size()>0&&userids.size()<1000)//如果太多就不管了这个条件了 predicates.add(root.<string>get("confirmuserid").in(userids)); } return query.where(predicates.toarray(new predicate[predicates.size()])).getrestriction(); } }; }
然后调用dao层方法传入where()方法返回的参数即可。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。