首页 > 解决方案 > 如何根据收到的参数使用 JPA 创建具有分页结果的自定义动态查询

问题描述

我想根据在我的搜索 API 端点中接收到的参数构建一个动态 JPA 查询,可能有 3 个参数:nome、cidade、causas(作为可以传递多个数字的数组):

@GetMapping("/search")
    public ResponseEntity<?> findByNome(Pageable pageable,
                                        @RequestParam Optional<String> nome,
                                    @RequestParam Optional<Long[]> causas,
                                    @RequestParam Optional<Long> cidade){

使用这 3 个参数,我需要使用 6 种可能的查询组合: *仅 cidade 通过 *cidade 和 causas *仅 nome *nome 和 causas *cidade 和 nome *cidade、nome 和 causas

为了达到同样的效果,我目前正在这样做:

 @Repository
public interface InstituicaoRepository extends PagingAndSortingRepository<Instituicao, Long> {

    //*only cidade passed
    Page<Instituicao> findByCidadeId(long cidadeId, Pageable pageable);
    //*cidade and causas
    @Query("select i from Instituicao i where i.cidadeId = ?1 and i.causaId in (?2)")
    Page<Instituicao> findByCidadeIdAndCausaIds(long cidadeId, Long[] causaIds, Pageable pageable);

    //*only nome
    Page<Instituicao> findByNomeContainingIgnoreCase(String nome, Pageable pageable);
    //*nome and causas
    @Query("select i from Instituicao i where lower(i.nome) like lower(concat('%',?1,'%')) and i.causaId in (?2)")
    Page<Instituicao> findByNomeAndCausaIds(String nomeInstituicao, Long[] causaIds, Pageable pageable);

    //*cidade and nome
    @Query("select i from Instituicao i where i.cidadeId = ?1 and lower(i.nome) like lower(concat('%',?2,'%'))")
    Page<Instituicao> findByCidadeIdAndNome(long cidadeId, String nomeInstituicao, Pageable pageable);
    //*cidade, nome and causas
    @Query("select i from Instituicao i where i.cidadeId = ?1 and lower(i.nome) like lower(concat('%',?2,'%')) and i.causaId in (?3)")
    Page<Instituicao> findByCidadeIdAndNomeAndCausaIds(long cidadeId, String nomeInstituicao, Long[] causaIds, Pageable pageable);

}

调用每个 InstituicaoRepository 的方法然后我手动使用 ifs 来检查哪些参数存在和不存在(这让我每次看我的代码都想哭)

关于改进它以提高效率的任何建议?请注意,需要包含 JPA 的分页。

标签: javaspringjpa

解决方案


你的方法不好,因为你的存储库中有很多方法,而且它会随着时间的推移而增长,它已经在 Spring.io 本身中提到,解决这个问题的更好方法是使用Specification,你可以扩展你的存储库JpaSpecificationExecutor并传递规范从其他层执行,它更干净,使您的代码易于阅读。还有一种更好的方法是 querydsl,您甚至不需要指定Specification,Spring 数据本身可以为您处理许多情况。从 Spring 本身阅读以下链接: advanced-spring-data-jpa-specifications-and-querydsl


推荐阅读