曾經想在 Spring Data JPA 中重寫查詢嗎?

工程 | Greg L. Turnquist | 2022 年 5 月 2 日 | ...

有時,無論您嘗試應用多少功能,似乎都無法讓 Spring Data JPA 在查詢傳送到 EntityManager 之前應用所有您想要的東西。

使用 3.0.0-SNAPSHOT(並作為 Spring Data 下一個里程碑釋出列車的目標),您現在可以在查詢傳送到 EntityManager 之前獲取查詢並“重寫”它。也就是說,您可以在最後一刻進行任何更改。

請看下面

示例 1. 使用 @Query 宣告 QueryRewriter

public interface MyRepository extends JpaRepository<User, Long> {

    @Query(value = "select original_user_alias.* from SD_USER original_user_alias",
                    nativeQuery = true, queryRewriter = MyQueryRewriter.class) // (1)
    List<User> findByNativeQuery(String param);

    @Query(value = "select original_user_alias from User original_user_alias",
                   queryRewriter = MyQueryRewriter.class) // (2)
    List<User> findByNonNativeQuery(String param);
}
  1. 這個純 SQL 查詢(感謝 nativeQuery)在呼叫之前將透過尚未定義的 MyQueryRewriter 進行路由。

  2. 這個 JPQL 查詢在交給 EntityManager 之前,也將透過相同的 MyQueryRewriter 進行路由。

然後,您可以自己編寫您的查詢重寫器,如下所示!

示例 2. 示例 QueryRewriter

public class MyQueryRewriter implements QueryRewriter {

    @Override
    public String rewrite(String query, Sort sort) {
        return query.replaceAll("original_user_alias", "rewritten_user_alias");
    }
}

好的,這個例子有點牽強。我們基本上只是改變了一個特定查詢別名的名稱。但你真的可以做任何你能想到的事情。這個鉤子讓你有機會改變一點(或很多!)。

只需確保在應用程式上下文中註冊一個 MyQueryRewriter 例項。無論您使用 Spring Framework 的基於 @Component 的註解,還是透過 @Configuration 類中的 @Bean 方法提供它,選擇權都在您。

警告

您的 QueryRewriter 在 Spring Data JPA 執行完所有檢查後被呼叫。您負責向 EntityManager 提供一個有效的查詢。

但是等等……​還有更多!

雖然您可以將 QueryRewriter 編寫為一個獨立的 bean,但也可以將其直接放在使用它的倉庫中!

示例 3. 提供 QueryRewriter 的倉庫

public interface MyRepository extends JpaRepository<User, Long>,
                                   QueryRewriter { // (1)

    @Query(value = "select original_user_alias.* from SD_USER original_user_alias",
                   nativeQuery = true, queryRewriter = MyRepository.class) // (2)
    List<User> findByNativeQuery(String param);

    @Query(value = "select original_user_alias from User original_user_alias",
                   queryRewriter = MyRepository.class) // (3)
    List<User> findByNonNativeQuery(String param);

    @Override
    default String rewrite(String query, Sort sort) { // (4)
        return query.replaceAll("original_user_alias", "rewritten_user_alias");
    }
}
  1. 讓您的倉庫介面繼承 QueryRewriter 介面。

  2. 將您的倉庫名稱插入到原生查詢的 @Query.queryRewriter 條目中。

  3. 將您的倉庫名稱插入到 JPQL 查詢的 @Query.queryRewriter 條目中。

  4. 覆蓋 rewrite(String,Sort) 方法並插入一個 default 值,然後 POOF,您就完成了!

溫馨提示:根據您具體要做的事情,您可能需要不止一個重寫器。

Spring Data JPA 不僅支援 Spring 的應用程式上下文,還支援基於 CDI 的環境。

愉快地查詢吧!

-Greg Turnquist

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有