【问题标题】:How to write dynamic query in JPA repository? Using Java springboot. Is Specification the answer?如何在 JPA 存储库中编写动态查询?使用Java springboot。规范是答案吗?
【发布时间】:2021-10-13 16:08:44
【问题描述】:

我在 JPA 存储库中有一个项目。我想使用 UNIONS 和一个响应参数从两个表中检索值,并且我在以下本机查询方面取得了成功。

Public interface resultRepository extends JpaRepository<Result, String>{


@Query(value= “SELECT ‘This is from Table 1’ AS MSG, COLUMN1, COLUMN2 COLUMN3, COLUMN4, COLUMN5 FROM TABLE1 
WHERE COLUMN1 = :column1 AND COLUMN2 = :column2 AND COLUMN3 = :column3 
UNION
SELECT ‘This is from Table 2’ AS MSG, COLUMN1, COLUMN2 COLUMN3, COLUMN4, COLUMN5 FROM TABLE2
WHERE COLUMN1 = :column1 AND COLUMN2 = :column2 AND COLUMN3 = :column3 ”, nativeQuery = true)
List<Result> getResultByParameters(@Param(“column1”) String column1, 
    @Param(“column2’)String column2,@Param(“column3’) String column3);

}

我的问题是。我希望“Where”子句是动态的。这样他们就可以通过这些参数中的任何一个进行搜索。无论是 column1 和 column2 还是 column2 和 column3。在我的前端,这些列参数将为 NULL。使用本机查询我无法决定选择哪些参数使用什么。

我正在阅读此链接中的规范。 https://dimitr.im/writing-dynamic-queries-with-spring-data-jpa

但我根本不明白。我还能收到自定义消息 (MSG) 吗?或者甚至使用联合搜索多个表?

【问题讨论】:

  • 你有没有想过这个问题?我遇到了确切的问题并遵循了相同的教程,但是当我尝试使用 repository.findAll(specifications, pageRequest) 时,我一直遇到 PropertyReferenceException "No property findAll found for type.."。它不应该这么难,但它是 Java,所以它就是。

标签: java spring-boot dynamic spring-data-jpa


【解决方案1】:

所以有很多方法可以在 JPA 中创建动态查询。让我们先列出其中的几个:

  1. 自定义存储库
  2. 规格
  3. JPA 存储库本身中的自定义查询(您已经编写过,但我将向您展示更灵活的解决方法)
  4. 查询DSL

自定义存储库

在这种方法中,基本上你创建一个接口,并在其中声明自定义方法。然后将此接口扩展为实际的存储库接口,并手动实现。这是处理自定义查询的最灵活方式。下面是例子:

public interface CustomRepository {
    public Result myCustomQueryMethod(String params);
}

public interface ResultRepository extends JpaRepository<Result, Long>, CustomRepository { ... }

public class CustomRepositoryImpl implements CustomRepository {

    @Autowired //@PersistentContext
    private EntityManager entityManager;
    
    public Result myCustomQueryMethod(String params) {
        String nativeSql = "...";
        // create query, execute it, and transform the results to object using object mapper or manually
    }
}

规格

下一个是规格(正如您已经提到的)。我不会在这里详细解释规范,因为它已经在您共享的教程链接中进行了解释。但是,如果您不想自己编写 SQL,您可以使用规范创建动态查询。但我猜你不能有带有规范的自定义预测(你想要的 MSG 参数的自定义选择子句)。

JPA 存储库中的自定义查询

以下是您的查询的略微修改版本,如果您要搜索的参数数量(在 where 子句中)是固定的,则可以达到您的目的:

@Query(value= “SELECT ‘This is from Table 1’ AS MSG, COLUMN1, COLUMN2 COLUMN3, COLUMN4, COLUMN5 FROM TABLE1 
WHERE (:column1 is null or COLUMN1 = :column1) AND (:column2 is null or COLUMN2 = :column2) AND (:column3 is null or COLUMN3 = :column3)
UNION
SELECT ‘This is from Table 2’ AS MSG, COLUMN1, COLUMN2 COLUMN3, COLUMN4, COLUMN5 
FROM TABLE2
WHERE (:column1 is null or COLUMN1 = :column1) AND (:column2 is null or COLUMN2 = :column2) AND (:column3 is null or COLUMN3 = :column3) ”, nativeQuery = true)
List<Result> getResultByParameters(@Param(“column1”) String column1, 
@Param(“column2’)String column2,@Param(“column3’) String column3);

看看我对 where 子句做了什么。

查询DSL

它再次类似于 Criteria API,但语法不同且更简单。您也可以使用 QueryDSL 创建类型安全的动态查询。这是更详细地解释 QueryDSL 的链接 - https://www.baeldung.com/querydsl-with-jpa-tutorial

【讨论】:

  • 好的,我需要知道我不能使用规范进行自定义投影。
  • 您最好的选择是使用自定义存储库,或者按照我上面提到的方式使用自定义查询(#3)。
【解决方案2】:

例如您可以按如下方式更改 SQL 请求 where 子句

WHERE COLUMN1 IN (:column1, :column3, :column3) OR COLUMN2 IN (:column1, :column3, :column3) OR COLUMN3IN (:column1, :column3, :column3) 

WHERE (:column1 IS NULL OR COLUMN1 = :column1) OR (:column1 IS NULL OR COLUMN2 = :column2) OR (:column1 IS NULL OR COLUMN3 = :column3)

这取决于你想要什么逻辑

【讨论】:

  • 这些列是不同大小的 CHAR,所以我会得到一个错误。输入变量或参数编号 7 无效。
猜你喜欢
  • 2020-08-10
  • 1970-01-01
  • 2022-09-22
  • 1970-01-01
  • 2013-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多