如何在Spring Data JPA中重写一个查询?(附实例)

658 阅读2分钟

有时,无论你尝试应用多少功能,似乎都不可能让Spring Data JPA在查询被发送到EntityManager 之前应用你想要的一切。

有了3.0.0-SNAPSHOT (目标是Spring Data的下一个里程碑版本),你现在有能力在查询被发送到EntityManager ,并 "重写 "它。也就是说,你可以在最后一刻做任何改动。

请看下面的例子。

例1.声明一个 QueryRewriter,使用@Query

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框架的一个基于@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的环境。

祝你查询愉快!