就很坑这个东西搞了一个下午的时间,终于搞会怎么用
对于想要查询 A and (B or C )或者 A And B And (C or D)
在jpa里你不能直接用and和or把字段拼起来,因为他并不会帮你自动加上括号,经过一下午的努力,学到了两种方法,但是我只用了其中一种,另一种感觉emmm挺复杂的而且效率和复用性都很差,就没去用。
1.这里我把差不多的两种都放在这里,首先是自己用QUERY注释写sql语句,这个复用性也很差好吧。然后差不多的就是,重新拼字段起来,把A and (B or C )变成A And B or A And C,就是把括号去掉就能直接使用,当然我遇到的情况是多条件判断查询的,这两种明显不符合我的要求,要写太多冗杂代码了,不符合自己完美主义hhhhhh
2.在JPA里可以使用Specification这个东西来对查询加入条件,我称他为条件构造器,具体使用:
Page findAll(Specification specification, Pageable pageable);
//实现自定义复杂条件和分页
然后在使用的时候,新建一个条件构造器,重写他的toPredicate方法,就能构造你想要的条件了。其中Predicate我理解为条件,围绕Predicate进行构造
EntityRepository.findAll(new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List list = new ArrayList<>();
Predicate predicateOr1 = criteriaBuilder.like(root.get("mac").as(String.class), "%" + finalSearch + "%");
Predicate predicateOr2 = criteriaBuilder.like(root.get("name").as(String.class), "%" + finalSearch + "%");
//构造or条件
Predicate predicateOr = criteriaBuilder.or(predicateOr1, predicateOr2);
//打上括号合并or语句
switch (admin.getType()) {
case 0:
break;
case 1:
list.add(criteriaBuilder.equal(root.get("pId").as(Long.class), admin.getId()));
break;
case 2:
list.add(criteriaBuilder.equal(root.get("sId").as(Long.class), admin.getId()));
break;
default:
return null;
}
//equal 为等于,Predicate条件中还提供了sql语句中如like等关键字,通过使用不同关键字的方法实现不同的功能
switch (status) {
case 0:
break;
case 1:
list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), 1));
break;
case 2:
list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), 3));
break;
default:
return null;
}
Predicate predicateAnd;//构造and条件
if (!list.isEmpty()) {
predicateAnd = criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
criteriaQuery.where(predicateOr, predicateAnd);
}else {
criteriaQuery.where(predicateOr);
}
//当你使用where的时候就已经把条件放进你的查询操作中了,因此不需要返回构造器给前面
return null;
}
},new PageRequest(page - 1, size));
这样就能轻松使用复杂查询了!!!!
更新一下今天遇到用list入参的问题
在查询后加in即可
如
List findByIdIn(List id);
更新!辣鸡jpa越用感觉越麻烦,今天项目把springboot更到2.0以上版本了,jpa也一起更新了,2.0以上jpa把findOne给删掉了,findById返回值更改为Optional包装的对象,需要用get方法才能get到实际需要的对象如:
AdminEntity teacher = adminEntityRepository.findById(body.getTeacherId()).get();
而且在底层我们可以看到,当查询对象为空,是直接抛出错误的,并不会返回null,这里需要我们注意
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
如果还想保持原来的逻辑功能,要不就trycatch搞起来,要不就自己写一个findByIdEqual还有最快的是在findById后加上.orElse(null)(其实我想改源码但是适用性太低了)