是否曾经想过在 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 查询也将通过相同的 MyQueryRewriter 进行路由,然后再将其传递给 EntityManager

然后,您可以编写自己的代码,如下所示!

示例 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 社区中所有即将举行的活动。

查看全部