Spring Boot JPA: Passing Multiple Values for the Same Parameter (JPQL)

岁酱吖の 提交于 2020-11-28 02:15:14

问题


I'm using JPQL to write SQL queries in JPA's CurdRepository interface. I was able to write more than one query with named parameters and they work like a charm.

However, my application requires that I match an unknown number of strings with more than one column in a table. To my knowledge, in SQL it'd look something like this:

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%" ... ...

I tried this in MySQL and it works fine. I couldn't figure out how to depict this in JPQL, however. I was able to pass multiple values for the IN clause by setting the named parameter to a List, as follows:

 @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)

I tried doing the same thing with the LIKE clause but I end up with 0 results if I pass more than 1 value. I face the same problem with the LOCATE clause as well.

Worst case scenario, I can set up one query that works on one String, and call it several times and then merge all the results. I'd very much rather avoid this however, as it'd be nothing more than a duct-tape solution.

I looked online for solutions for hours but haven't found anything that addresses my concern. Any tip is highly appreciated.

Thanks.


回答1:


Because @Query needs to be fixed at compile time using JPQL or even native query will make this kind of things hard to implement especially in a type safe way.

So I realize you are after JPQL solution but this is an awesome opportunity to learn and take advantage of Specification interface and JPA's CriteriaQuery. This is exactly it is for.

Take a look at the following repository:

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[]{}));
            }
        };
    }

}

It might look a bit complex but actually it is not when you get familiar with it. Usage is simple, like:

@Resource
private Table1Repository repo;
repo.findAll(Table1Repository.multiLikeColumn1(Arrays.asList("%X%","%Z%")))


来源:https://stackoverflow.com/questions/54154045/spring-boot-jpa-passing-multiple-values-for-the-same-parameter-jpql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!