使用Spring Data Jpa的CriteriaQuery一个陷阱
使用SpringDataJpa的CriteriaQuery进行动态条件查询时,可能会遇到一个陷阱,当条件为空时,查询不到任何结果,并不是期望的返回所有结果。这是为什么呢?
例如下述代码,当predicates为空时,返回结果总是为空。
publicPagelistVmhostSpecWithRelationByPage(Stringname){ Specification spec=(root,cq,cb)->{ root.join("user",JoinType.LEFT); root.join("tenant",JoinType.LEFT); List predicates=newArrayList<>(); ...... returncb.or(predicates.toArray(newjavax.persistence.criteria.Predicate[0])); }; PageRequestpagable=PageRequest.of(0,5); Page page=vmhostSpecWithRelationDao.findAll(spec,pagable); returnpage; }
看下or的注释就明白了,因为空条件总是为false,而and的空条件总是为true。所以,如果最后是and就没有问题,只有or的时候有问题。
publicinterfaceCriteriaBuilder{ /** *Createaconjunctionofthegivenrestrictionpredicates. *Aconjunctionofzeropredicatesistrue. *@paramrestrictionszeroormorerestrictionpredicates *@returnandpredicate */ Predicateand(Predicate...restrictions); /** *Createadisjunctionofthegivenrestrictionpredicates. *Adisjunctionofzeropredicatesisfalse. *@paramrestrictionszeroormorerestrictionpredicates *@returnorpredicate */ Predicateor(Predicate...restrictions); }
所以正确的写法应该这样:
publicPagelistVmhostSpecWithRelationByPage(Stringname){ Specification spec=(root,cq,cb)->{ root.join("user",JoinType.LEFT); root.join("tenant",JoinType.LEFT); List predicates=newArrayList<>(); ...... returnpredicates.isEmpty()?cb.conjunction():cb.or(predicates.toArray(newjavax.persistence.criteria.Predicate[0])); }; PageRequestpagable=PageRequest.of(0,5); Page page=vmhostSpecWithRelationDao.findAll(spec,pagable); returnpage; }
如果条件为空则返回一个空conjunction,也就是空的and,总是为true。
公司项目的代码中常见这种写法:
publicPagelistVmhostSpecWithRelationByPage(Stringname){ Specification spec=(root,cq,cb)->{ root.join("user",JoinType.LEFT); root.join("tenant",JoinType.LEFT); List predicates=newArrayList<>(); ...... if(predicates.isEmpty()){ cq.where(); }else{ cq.where(cb.or(predicates.toArray(newjavax.persistence.criteria.Predicate[0]))); } returncq.getRestriction(); }; PageRequestpagable=PageRequest.of(0,5); Page page=vmhostSpecWithRelationDao.findAll(spec,pagable); returnpage; }
也能正常工作,但是其实没有必要在toPredicate方法中调用where,toPredicate只需要返回条件,外层会调用where。
publicinterfaceSpecificationextendsSerializable{ /** *CreatesaWHEREclauseforaqueryofthereferencedentityinformofa{@linkPredicate}forthegiven *{@linkRoot}and{@linkCriteriaQuery}. * *@paramrootmustnotbe{@literalnull}. *@paramquerymustnotbe{@literalnull}. *@paramcriteriaBuildermustnotbe{@literalnull}. *@returna{@linkPredicate},maybe{@literalnull}. */ @Nullable PredicatetoPredicate(Root root,CriteriaQuery>query,CriteriaBuildercriteriaBuilder); }
本文作者:钟潘
本文链接:http://zhongpan.tech/2020/07/20/035-a-trap-for-using-criteriaquery/
以上就是CriteriaQuery使用的一个陷阱的详细内容,更多关于CriteriaQuery陷阱的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。