如何在JPA自定义findAll查询中用ExampleMatcher实现动态条件查询
问题:JPA单调用实现动态条件查询
需求:调用JPA仓库时,传入stateId则按该值过滤县数据;stateId为空时返回所有县数据,要求单次仓库调用完成,无需分两次执行。
当前尝试的代码
业务逻辑代码:
StateCountyId stateCountyId = new StateCountyId(); StateCounty stateCounty = new StateCounty(); if(null != stateId){ stateCountyId.setStateId(stateId); } stateCounty.setStateCountyId(stateCountyId); return countiesRepository.findAllByStateCountyIdStateIdOrderByStateCountyIdCountyNameAsc (Example.of(stateCounty, ExampleMatcher.matchingAll().withIgnoreCase())) .stream().map(this::countyAsDropDown).collect(Collectors.toList());
仓库接口:
@Repository public interface CountiesRepository extends JpaRepository<StateCounty, StateCountyId> { List<StateCounty> findAllByStateCountyIdStateIdOrderByStateCountyIdCountyNameAsc(Example stateId); }
实体类:
@Entity @Builder public class StateCounty implements Serializable { @EmbeddedId StateCountyId stateCountyId; @Column(name = "CODE_NBR") private String codeNbr; } @Embeddable @EqualsAndHashCode public class StateCountyId implements Serializable { @Column(name = "STATE_ID") private String stateId; @Column(name = "COUNTY_NAME") private String countyName; }
直接传参的问题
若直接传入字符串stateId调用如下方法:
countiesRepository.findAllByStateCountyIdStateIdOrderByStateCountyIdCountyNameAsc (stateId) .stream().map(this::countyAsDropDown).collect(Collectors.toList());
stateId有效时可正常查询,但stateId为空时会返回空结果,不符合返回全量数据的预期。
解决方案
方案1:使用Example+忽略空值属性
修正仓库接口
无需自定义方法,直接使用JpaRepository自带的findAll方法:
@Repository public interface CountiesRepository extends JpaRepository<StateCounty, StateCountyId> { }
调整业务逻辑代码
关键是给ExampleMatcher添加withIgnoreNullValues(),让JPA忽略空值属性,不生成对应查询条件:
StateCounty stateCounty = new StateCounty(); StateCountyId stateCountyId = new StateCountyId(); if (stateId != null) { stateCountyId.setStateId(stateId); } stateCounty.setStateCountyId(stateCountyId); // 配置匹配器:忽略空值属性,避免空stateId生成IS NULL条件 ExampleMatcher matcher = ExampleMatcher.matchingAll() .withIgnoreCase() .withIgnoreNullValues(); // 定义排序规则 Sort sort = Sort.by(Sort.Direction.ASC, "stateCountyId.countyName"); // 调用自带的findAll方法 return countiesRepository.findAll(Example.of(stateCounty, matcher), sort) .stream() .map(this::countyAsDropDown) .collect(Collectors.toList());
方案2:使用@Query编写动态SQL
这种方式更直观,直接在SQL中处理动态条件:
仓库接口新增方法
@Repository public interface CountiesRepository extends JpaRepository<StateCounty, StateCountyId> { @Query("SELECT sc FROM StateCounty sc WHERE (:stateId IS NULL OR sc.stateCountyId.stateId = :stateId) ORDER BY sc.stateCountyId.countyName ASC") List<StateCounty> findCountiesByStateId(@Param("stateId") String stateId); }
业务逻辑调用
直接调用该方法即可,无需额外处理:
return countiesRepository.findCountiesByStateId(stateId) .stream() .map(this::countyAsDropDown) .collect(Collectors.toList());
内容的提问来源于stack exchange,提问作者VKP
相关产品推荐
相关产品推荐

