Spring boot JPA的复杂查询

就很坑这个东西搞了一个下午的时间,终于搞会怎么用
对于想要查询 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)(其实我想改源码但是适用性太低了)

你可能感兴趣的:(Spring boot JPA的复杂查询)