【问题标题】:Spring Data - Why it's not possible to have paging with native querySpring Data - 为什么不能使用本机查询进行分页
【发布时间】:2015-04-16 06:21:26
【问题描述】:

假设我们有一个名为MyEntity 的实体。可以使用@Query 和命名查询来查询可分页结果,例如

 @Query(value = "select e from MyEntity e where e.enabled = true")
 Page<MyEntity> findAllEnabled(Pageable pageable);

但是,用原生查询是不可能达到同样的效果的,所以这个

 @Query(value = "select * from my_entity where enabled = true", nativeQuery = true)
 Page<MyEntity> findAllEnabled(Pageable pageable);

行不通。

这背后的原因是什么?是否可以使 Pageable 与原生查询一起使用?

【问题讨论】:

标签: java spring spring-data-jpa


【解决方案1】:

我不知道这是否仍然与您相关:至少在 Spring Data JPA 1.9.4 中您可以指定两个查询。

给定一个存储库:

interface FoobarEntityRepository extends JpaRepository<FoobarEntity, Integer> {
    Page findFoobarsSpecialQuery(String someParameter, final Pageable pageable);
}

您可以向您的实体添加 2 个本机查询,一个用于查询本身,一个用于计数语句:

@Entity
@SqlResultSetMappings({
    @SqlResultSetMapping(name = "SqlResultSetMapping.count", columns = @ColumnResult(name = "cnt"))
})
@NamedNativeQueries({
    @NamedNativeQuery(
            name = "FoobarEntity.findFoobarsSpecialQuery",
            resultClass = DailyPictureEntity.class,
            query = "Select * from foobars f where someValue = :someParameter "
    ),
    @NamedNativeQuery(
            name = "FoobarEntity.findFoobarsSpecialQuery.count",
            resultSetMapping = "SqlResultSetMapping.count",
            query = "Select count(*) as cnt from foobars f where someValue = :someParameter "
    )
})
FoobarEntity {
}

诀窍是使用后缀.count 指定计数查询。这也适用于 Spring Data @Query 注释。

但请注意,您需要一个用于计数查询的 SQL 结果集映射。

这确实很好用。

【讨论】:

  • 我知道这已经有几年历史了。但是你有没有机会在 github 上实现这个的示例代码?我用谷歌搜索了这个,没有太多关于这个的文档。谢谢
【解决方案2】:

这是描述,在 spring data jpa 文档 (http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/) 中给出

原生查询@Query 注解允许执行原生查询 通过将 nativeQuery 标志设置为 true。请注意,我们目前不 支持对本机查询执行分页或动态排序 因为我们必须操纵声明的实际查询,我们不能这样做 这对于原生 SQL 来说是可靠的。

JPQL 抽象了 SQL 实现及其提供者的细节,并让 ORM 框架负责生成正确的 SQL。

  1. 所以通过使用 JPQL 形式的分页,Spring 只需要生成正确的 JPQL,它会在 ORM 级别进行解释以更正 SQL。

  2. 虽然使用 SQL 这样做,但意味着 Spring 知道如何为绝大多数 RDBMS 生成正确的 SQL,复制 ORM 功能,这是太多的开销。

【讨论】:

    【解决方案3】:

    有一种方法可以将 Pageable 与具有 Spring 数据的 SpEL 容量的本机查询一起使用,提到 here

    您可以在this repository 中找到示例。

    /**
         * @see DATAJPA-564
         */
        @Query(
                value = "select * from (select rownum() as RN, u.* from SD_User u) where RN between ?#{ #pageable.offset -1} and ?#{#pageable.offset + #pageable.pageSize}",
                countQuery = "select count(u.id) from SD_User u", nativeQuery = true)
        Page<User> findUsersInNativeQueryWithPagination(Pageable pageable);
    

    如果fromclause 或您的本机查询中有子查询并且您希望对其应用动态排序,则排序功能将无法正常工作。可以这样做的方法是在where 子句中移动子查询。
    如果Pageable 中有Sort 对象,Spring 数据将附加到您的请求" order by "end。 (使用 Spring 数据 1.10.3)

    如果可能,更好的方法是在 jpql 中转换原生查询。

    【讨论】:

    • Atm 似乎可以将@Query 注释(不确定本机)与返回 Page 对象的存储库方法一起使用,尽管当我想将查询移动到 orm.xml 时发现问题。不需要 value 和 count 查询...只需正常放置查询即可。
    猜你喜欢
    • 2017-10-16
    • 2018-01-27
    • 1970-01-01
    • 2023-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-25
    • 2019-06-21
    相关资源
    最近更新 更多