JPA多对多IN查询传入空列表返回空结果如何解决
问题根因
你遇到的空列表返回空的问题,本质是SQL中IN操作符传入空集合时,语法解析为IN (),不会匹配任何数据,所以只要任意一个入参为空就返回空结果。另外你现有Repository方法的参数类型有误:入参应该是List<Foo>和List<Bar>,不是List<MyEntity>。
解决方案
方案1:用Specification动态拼接查询(推荐,灵活度最高)
这种方案可以根据入参是否为空动态决定是否拼接对应条件,适合复杂的动态查询场景。
首先修改Repository接口,继承JpaSpecificationExecutor:
public interface MyEntityRepository extends JpaRepository<MyEntity, Long>, JpaSpecificationExecutor<MyEntity> { }
然后编写动态构建查询条件的工具方法:
import org.springframework.util.CollectionUtils; import javax.persistence.criteria.Predicate; import java.util.ArrayList; import java.util.List; public Specification<MyEntity> buildDuplicateCheckSpec(List<Foo> foos, List<Bar> bars) { return (root, query, cb) -> { List<Predicate> predicates = new ArrayList<>(); // Foo列表不为空时才加Foo匹配条件 if (CollectionUtils.isNotEmpty(foos)) { predicates.add(root.get("foos").in(foos)); } // Bar列表不为空时才加Bar匹配条件 if (CollectionUtils.isNotEmpty(bars)) { predicates.add(root.get("bars").in(bars)); } // 如果两个列表都为空,可根据业务需求调整逻辑,比如不允许新增两个属性都为空的实体 return cb.and(predicates.toArray(new Predicate[0])); }; }
调用时直接传入构建好的Specification即可:
List<MyEntity> existEntities = myEntityRepository.findAll(buildDuplicateCheckSpec(foos, bars)); // 判断existEntities非空就拦截新增
方案2:用@Query写固定JPQL查询
如果不想引入Specification,也可以在JPQL中加入空集合判断,自动跳过空参数的校验:
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> { @Query("select m from MyEntity m where " + "(:foos is empty or m.foos in :foos) " + "and (:bars is empty or m.bars in :bars)") List<MyEntity> findAllByFoosInAndBarsIn(@Param("foos") List<Foo> foos, @Param("bars") List<Bar> bars); }
注意事项
如果你的业务规则要求完全匹配Foo和Bar的集合(而不是包含任意一个入参中的元素),需要调整查询逻辑为exists子查询匹配全量元素,避免IN操作符匹配部分元素就返回结果的问题。
内容的提问来源于stack exchange,提问作者jared
相关产品推荐
相关产品推荐

