Spring Boot JPA:为同一参数传递多个值 (JPQL)

Posted

技术标签:

【中文标题】Spring Boot JPA:为同一参数传递多个值 (JPQL)【英文标题】:Spring Boot JPA: Passing Multiple Values for the Same Parameter (JPQL) 【发布时间】:2019-06-06 19:40:37 【问题描述】:

我正在使用 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 中描述这一点。通过将命名参数设置为List,我能够为IN 子句传递多个值,如下所示:

 @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 子句也面临同样的问题。

在最坏的情况下,我可以设置一个对一个字符串起作用的查询,并多次调用它,然后合并所有结果。不过,我宁愿避免这种情况,因为它只不过是一种胶带解决方案。

我在网上寻找了几个小时的解决方案,但没有找到任何解决我问题的方法。非常感谢任何提示。

谢谢。

【问题讨论】:

你能访问你的spring存储库使用的EntityManager吗?我的意思是,你有可以注入 EntityManager 的服务吗? @CarlitosWay 我有服务,但我没有使用EntityManager。我有一个实现CrudRepository 的存储库接口,并使用该服务从所述存储库调用不同的方法。 【参考方案1】:

因为@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%")))

【讨论】:

更好的是,可以执行以下操作来返回分页结果:repo.findAll(Table1Repository.multiLikeColumn1(Arrays.asList("%X%","%Z%")),new PageRequest(pagenum, page_offset))

以上是关于Spring Boot JPA:为同一参数传递多个值 (JPQL)的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot jpa 中将多个外键映射到同一个主键

如何只扫描一个具体的 JPA 实体,但不是所有实体都使用 spring-boot 放在同一个包中?

在命令行 Spring Boot 中传递多个参数

如何在单个 JDBC 连接中执行多个 JPA 查询

具有多个数据源和外部配置的 Spring Boot,Spring JPA

带有查询 Spring-Boot jpa 1.5 的可选参数