【问题标题】:Spring Data paginate and sort a NamedNativeQuery (JPA-Hibernate-MySql)Spring Data 对 NamedNativeQuery (JPA-Hibernate-MySql) 进行分页和排序
【发布时间】:2019-08-14 21:20:57
【问题描述】:

我在 Spring Data (JPA Hibernate MySQL) 应用程序中使用 NamedNativeQueries 和 SqlResultSetMappings,并且我在分页方面取得了成功,但在排序方面没有成功。

我尝试了两种形式的查询:

@NamedNativeQuery(
  name = "DatasetDetails.unallocatedDetailsInDataset",
  resultClass = DatasetDetails.class,
  resultSetMapping = "DatasetDetails.detailsForAllocation",
  query = "SELECT dd.id, fk_datasets_id, fk_domains_id, fk_sources_id, dom.name AS domain, " +
  "src.name AS source " +
  "FROM datasets AS d " +
  "JOIN datasets_details AS dd ON dd.fk_datasets_id = d.id " +
  "JOIN sources AS src ON src.id = dd.fk_sources_id " +
  "JOIN domains AS dom ON dom.id = dd.fk_domains_id " +
  "WHERE fk_datasets_id = :datasetId " +
  "AND dd.id NOT IN (" +
  "SELECT fk_datasets_details_id from allocations_datasets_details)  \n/* #page */\n"),

第二个只是在第二个查询中使用计数表示法,而不是使用#page 表示法。

@NamedNativeQuery(
  name = "DatasetDetails.unallocatedDetailsInDataset.count",
  resultClass = DatasetDetails.class,
  resultSetMapping = "DatasetDetails.detailsForAllocation",
  query = "SELECT count(*)
....

这两种方法都适用于分页,但排序被忽略了。

这里是存储库:

public interface DatasetDetailsRepository extends PagingAndSortingRepository<DatasetDetails, Long> {
    @Query(nativeQuery = true)
    List<DatasetDetails> unallocatedDetailsInDataset(@Param("datasetId") long datasetId,
                                                     @Param("page") Pageable page);
}

pageable 是这样组装的:

Sort sort = Sort.by(Sort.Order.asc(DatasetDetails.DOMAIN), Sort.Order.asc(DatasetDetails.SOURCE));
Pageable page = PageRequest.of(page, limit, sort);

没有抛出错误,但排序根本没有完成,也没有生成 ORDER BY。

显式添加 ORDER BY #{#page} 之类的内容不会编译。

【问题讨论】:

  • 您是如何在 NamedNativeQuery 上获得分页的?您在查询中使用了页面对象还是在 NamedNativeQuery 中以任何方式传递了它?我注意到即使您传入了 pageable 参数,但返回类型是 List 而不是 Page。

标签: java spring-data-jpa


【解决方案1】:

我遇到了同样的问题,我必须使用 NamedNativeQuery 按不同的列和方向动态过滤/排序;显然排序被忽略了。我找到了这个解决方法,它不一定很好,但它确实有效:

对于存储库:

List<MyEntity> findMyEntities(
    @Param("entityId") long entityId,
    @Param("sortColumn") String sortColumn,
    @Param("sortDirection") String sortDirection,
    Pageable page);

本机查询如下所示:

@NamedNativeQueries({
  @NamedNativeQuery(name = "MyEntity.findMyEntities",
      query = "select e.field1, e.field2, ..." +
              " from my_schema.my_entities e" +
              " where condition1 and condtition2 ..." +
              " order by " +
              "   CASE WHEN :sortColumn = 'name'      and :sortDirection = 'asc'  THEN e.name      END ASC," +
              "   CASE WHEN :sortColumn = 'birthdate' and :sortDirection = 'asc'  THEN e.birthdate END ASC," +
              "   CASE WHEN :sortColumn = 'name'      and :sortDirection = 'desc' THEN e.name      END DESC," +
              "   CASE WHEN :sortColumn = 'birthdate' and :sortDirection = 'desc' THEN e.birthdate END DESC" +
  ),
  @NamedNativeQuery(name = "MyEntity.findMyEntities.count",
          query = "select count(*) from my_schema.my_entities e" +
                  " where condition1 and condtition2 ..." +
                  "  and :sortColumn = :sortColumn and :sortDirection = :sortDirection"
  )
})

注意在count查询中我使用:sortColumn:sortDirection这2个冗余条件,因为一旦在repository函数中指定为@Param,你需要在实际查询中使用它们。

在调用该函数时,在我的服务中,我有一个指示方向的布尔值和一个指示排序列的字符串,如下所示:

public Page<MyEntity> serviceFindFunction(Long entityId, String sortColumn, Boolean sortDirection, Integer pageNumber, Integer pageSize) {
    String sortDir = (sortDirection) ? 'asc' : 'desc';
    Pageable pageable = new PageRequest(pageNumber, pageSize); // Spring Data 1.0 syntax

    // for Spring Data 2.0, as you were using, simply:
    // Pageable pageable = PageRequest.of(pageNumber, pageSize);

    return entityRepository.findMyEntities(entityId, sortColumn, sortDir, pageable)
}

我不喜欢的两件事是计数查询中 sortColumnsortDirection 参数的冗余使用,以及我编写 order by statement 的方式。有单独的CASE 语句的原因是因为我对排序的列有不同的数据类型,如果它们不兼容(例如nvarchardate),查询将失败并出现错误:

Conversion failed when converting date and/or time from character string

我也可以嵌套条件,即首先为方向制作一个案例,为列制作一个内部案例,但我的 SQL 技能只到此为止。

希望这会有所帮助!非常欢迎任何反馈或改进。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-10
    • 2015-03-24
    • 2013-07-25
    • 2022-06-10
    • 2012-12-16
    • 2019-07-20
    • 1970-01-01
    相关资源
    最近更新 更多