Spring Data - 分页请求 - 按函数排序

5

我正在尝试在基于Spring 4.1.1.RELEASE和Hibernate 4.2.16.Final的Java应用程序中实现分页。

我有以下代码:

PageRequest pageRequest = new PageRequest(pageNumber, pageSize, new Sort(new Order(Direction.DESC, "name"))
Page page = myRepository.findAll(specification, pageRequest);

一切都运行良好。但是现在我希望按SQL函数值排序,例如:ORDER BY CHAR_LENGTH(name)

当我在@org.springframework.data.jpa.repository.Query中输入这样的语句时,它可以完美运行,例如:

public class MyRepository {
  @Query("select e from MyEntity e order by CHAR_LENGTH(e.name)")
  public List<MyEntity> findAllOrderedByNameLength();
}

不幸的是,我不能使用PageRequest完成这个任务。当我将ORDER BY CHAR_LENGTH(name)作为一个参数传递给PageRequest时:

PageRequest pageRequest = new PageRequest(pageNumber, pageSize, new Sort(new Order(Direction.DESC, "ORDER BY CHAR_LENGTH(name)"))
Page page = myRepository.findAll(specification, pageRequest);

以下异常被抛出:
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property CHAR found for type MyEntity!

在数据库中创建一个视图不是更容易吗? - Neil McGuigan
2个回答

2
它在查询中起作用的原因是Hibernate将无法识别的任何内容直接传递到SQL中,这不是JPA的特性,因此可能无法与其他提供程序一起使用。
一个不错的选择是实现自定义Order类,并使用它代替。您可以在this blog中找到详细的说明。使用博客中完全实现的方式,您将使用OrderBySqlFormula.sqlFormula("CHAR_LENGTH(name) desc") 更新: 所提出的解决方案仅适用于Hibernate,不能与Spring Data代码一起使用,后者需要org.springframework.data.domain.Sort.Order而不是org.hibernate.criterion.Order

好的,但它需要“Criteria”对象,而我没有参考。在我的代码中,只有“Specification”和“PageRequest”被传递到存储库,并且它非常好用,因为它返回了我需要返回给客户端的“Page”对象(它包含元素的总数和页面的总数)。在您的示例中,我需要从头开始实现这样的逻辑-首先计算,然后选择并将所有内容设置为Page对象。 - Konrad
您不需要引用Criteria。如果您正在引用方法toSqlString(),它在org.hibernate.criterion.Order中声明并在内部使用。 - Predrag Maric
您可以像这样使用它:new PageRequest(pageNumber, pageSize, new Sort(OrderBySqlFormula.sqlFormula("CHAR_LENGTH(name) desc"))) - Predrag Maric
1
好的,但是问题在于我需要将org.springframework.data.domain.Pageable传递给我的仓库,而我的仓库需要org.springframework.data.domain.Sort,但我无法构建它,因为我没有org.springframework.data.domain.Sort.Order。我只有不兼容的org.hibernate.criterion.Order - Konrad
哦,你说得对。抱歉。我看到了“hibernate”标签,完全忘记这是一个Spring Data的问题了。 - Predrag Maric

1
你可以使用 @Formula 并定义一个自定义字段用于 CHAR_LENGTH(name) 表达式的排序。
例如,参见 这里

听起来很有趣。但是,是否可能在需要时动态创建这些公式?问题在于排序属性的名称(在本例中为“name”)来自客户端。我唯一需要做的就是将此属性名称包装在函数调用中并传递给存储库。由于存在多个实体和多个可能的排序列,因此维护每个实体的公式属性可能会有问题。 - Konrad
另外,在使用@Formula时,Hibernate存在一个已经存在了10年的bug。在您使用它的用例中可能不会出现,但在尝试转换为此实体的其他本地查询中,您将会遇到错误。 - bytor99999

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接