我正在使用JPQL在JPA的CurdRepository
界面中编写SQL查询。我能够用命名参数编写多个查询,它们就像一个魅力一样工作。
但是,我的应用程序要求我将未知数目的字符串与一个表中的多个列匹配。据我所知,在SQL中看起来像这样:
SELECT * FROM TABLE WHERE COLUMN_1 LIKE "%string_1%" OR COLUMN_1 LIKE"%string_2%" ... OR COLUMN_2 LIKE "%string_1%" OR COLUMN_2 LIKE "%string_2%" ... ...
我在MySQL中试过了,效果很好。但是,我不知道如何在JPQL中进行描述。通过将命名参数设置为IN
,我能够为List
子句传递多个值,如下所示:
@Query("SELECT t FROM Table t WHERE TABLE_ID IN (:table_ids)")
public Page<Table> findByParameters(@Param("table_ids") List<Integer> table_ids, Pageable page)
我尝试使用LIKE
子句做同样的事情,但是如果我传递的值超过1,最终结果为0。我也遇到LOCATE
子句相同的问题。
在最坏的情况下,我可以设置一个对一个String起作用的查询,并多次调用它,然后合并所有结果。但是,我宁愿避免这种情况,因为它只不过是一条胶带解决方案。
我在网上寻找解决方案已有几个小时,但没有找到任何解决我的问题的方法。任何提示都将受到高度赞赏。
谢谢。
答案 0 :(得分:2)
因为@Query
需要在编译时使用JPQL进行修复,否则即使是本机查询也将使这种事情难以实现,尤其是以一种类型安全的方式。
因此,我意识到您正在使用JPQL解决方案,但这是学习和利用Specification
界面和JPA的CriteriaQuery的绝佳机会。就是这样。
看看以下存储库:
public interface Table1Repository // to use specifications in queries
extends JpaRepository<Table1, Long>, JpaSpecificationExecutor<Table1> {
@SuppressWarnings("serial")
public static Specification<Table1> multiLikeColumn1(List<String> likePatterns) {
return new Specification<Table1>() {
@Override
public Predicate toPredicate(Root<Table1> root, CriteriaQuery<?> query,
CriteriaBuilder criteriaBuilder) {
Path<String> column1 = root.get("column1");
// create a Predicate for each "column1 like 'xy%az%' you need
List<Predicate> predicates = likePatterns.stream()
.map(likePattern -> criteriaBuilder.like(column1, likePattern))
.collect(Collectors.toList());
// then "concatenate" list of likes with "OR"
return criteriaBuilder.or(predicates.toArray(new Predicate[]{}));
}
};
}
}
它看起来可能有点复杂,但是实际上当您熟悉它时并不是这样。用法很简单,例如:
@Resource
private Table1Repository repo;
repo.findAll(Table1Repository.multiLikeColumn1(Arrays.asList("%X%","%Z%")))