使用Spring Data Jpa的CriteriaQuery进行动态条件查询时,可能会遇到一个陷阱,当条件为空时,查询不到任何结果,并不是期望的返回所有结果。这是为什么呢?
例如下述代码,当predicates为空时,返回结果总是为空。
public PagelistVmhostSpecWithRelationByPage(String name) { Specification spec = (root, cq, cb) -> { root.join("user", JoinType.LEFT); root.join("tenant", JoinType.LEFT); List predicates = new ArrayList<>(); ...... return cb.or(predicates.toArray(new javax.persistence.criteria.Predicate[0])); }; PageRequest pagable = PageRequest.of(0, 5); Page page = vmhostSpecWithRelationDao.findAll(spec, pagable); return page; }
看下or的注释就明白了,因为空条件总是为false,而and的空条件总是为true。所以,如果最后是and就没有问题,只有or的时候有问题。
public interface CriteriaBuilder {
Predicate and(Predicate... restrictions);
Predicate or(Predicate... restrictions);
}
所以正确的写法应该这样:
public PagelistVmhostSpecWithRelationByPage(String name) { Specification spec = (root, cq, cb) -> { root.join("user", JoinType.LEFT); root.join("tenant", JoinType.LEFT); List predicates = new ArrayList<>(); ...... return predicates.isEmpty() ? cb.conjunction() : cb.or(predicates.toArray(new javax.persistence.criteria.Predicate[0])); }; PageRequest pagable = PageRequest.of(0, 5); Page page = vmhostSpecWithRelationDao.findAll(spec, pagable); return page; }
如果条件为空则返回一个空conjunction,也就是空的and,总是为true。
公司项目的代码中常见这种写法:
public PagelistVmhostSpecWithRelationByPage(String name) { Specification spec = (root, cq, cb) -> { root.join("user", JoinType.LEFT); root.join("tenant", JoinType.LEFT); List predicates = new ArrayList<>(); ...... if (predicates.isEmpty()) { cq.where(); } else { cq.where(cb.or(predicates.toArray(new javax.persistence.criteria.Predicate[0]))); } return cq.getRestriction(); }; PageRequest pagable = PageRequest.of(0, 5); Page page = vmhostSpecWithRelationDao.findAll(spec, pagable); return page; }
也能正常工作,但是其实没有必要在toPredicate方法中调用where,toPredicate只需要返回条件,外层会调用where。
public interface Specificationextends Serializable { @Nullable Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder criteriaBuilder); }
本文作者: 钟潘
本文链接: http://zhongpan.tech/2020/07/20/035-a-trap-for-using-criteriaquery/
以上就是CriteriaQuery使用的一个陷阱的详细内容,更多关于CriteriaQuery 陷阱的资料请关注考高分网其它相关文章!



