如何将PageRequest按照数字值作为字符串进行排序

10

我目前有一个系统,可以过滤和排序数据库记录,并将它们作为分页对象返回。其中一行如下:

final PageRequest request = new PageRequest(this.pagingSettings.getPageNumber(),
            this.pagingSettings.getPageSize(), sortDirection, sortedBy);

这个代码工作得很好,但现在我遇到了以下情况。 我正在尝试对房屋编号进行排序,在我的Postgres数据库中是一个varchar。 例如,我们有1、12、111、1004,还有1A或36-BASEMENT。 当对这些(字符)值进行排序时,它们将按以下方式排序:1、1004、111、12、1A、...

因此,sortedBy 现在是一个字符串,在这种情况下是 houseNumber。 我发现使用 Postgres 的 ORDER BY 参数 ... ORDER BY NULLIF(regexp_replace(container_number, E'\\D', '', 'g'), '')::int";,排序将完全按照我想要的方式进行:1、1A、12、111、...

然而,只是将 sortedBy 字符串更改为 sortedBy = "NULLIF(regexp_replace(container_number, E'\\D', '', 'g'), '')::int"; 似乎不起作用。

有没有人有建议如何在不更改数据库的情况下将字符值在 PageRequest 数值排序?


你解决了这个问题吗? - Muhammad Waqas Dilawar
3个回答

3
基本上,您需要做两件事:
  1. 实现自定义比较器
  2. 注释实体类

广告.1.

public class HouseComparator implements Comparator<House> {
    @Override
    public int compare(House h1, House h2) {

        String s1 = h1.getHouseNumber().split("[^0-9]")[0];
        String s2 = h2.getHouseNumber().split("[^0-9]")[0];

        return s1.compareTo(s2);
    }
}

您需要对用例进行更好的处理。上述比较器表示,当以较小的数字开头时,h1 小于 h2,反之亦然。对于这个比较器,12A 等于 12B,但这取决于您。

广告.2.

@SortComparator(HouseComparator.class)
List<House> findByHouseNumber(Pageable pageable);

1
我不确定这是否是我所寻找的。PageRequest使得可以对对象总列表进行分页响应。这意味着我只有200个对象中的10个可用。我不确定如何将您的解决方案适配到这里。对我来说,这似乎需要在此处进行后排序。 我将看看如何适配这个解决方案,并报告它的作用。 - Joetjah
我正在使用 Page<House> houses = this.houseRepository.findAll(request); 那么我应该在哪里使用这个 Comparator 呢? - Joetjah
你使用什么数据库? - xenteros
我使用Postgres数据库。 - Joetjah

3
假设您有一个实体,其中包含一个字符串字段,并且您想要使用JPA Pageable像Long一样对其进行排序。
因此,您需要执行以下操作:(请记住,这仅适用于Oracle数据库)
  1. 在实体中添加一个新字段,类型为Long
  2. 在getter方法中使用@Formula注解并调用to_number()来处理新的字段
@Entity
public class testEntity{
         private String oldField;  //Getter and Setter

         private Long newField; //Setter

         @Formula(value = "to_number(oldField)")
         public Long getNewField() {
                return newField;
         } 
 }
  1. 在你的服务中找到已排序的字段并将其更改为 newfiled
 if (Objects.nonNull(pagingRequest.getSort()) && pagingRequest.getSort().getFieldName().equals("oldField")) {
            pagingRequest.getSort().setFieldName("newField");
 }

1
在我看来,这个解决方案是最好的,但是我有一个小更新: a) 当你声明字段时,将@Formula放在周围会更好看(不需要在getter上放置它) b) 当你遇到像“Formula mappings are currently not supported”这样的错误时,你可能需要添加@NotAudited注释(更多信息请参见:https://dev59.com/SVcP5IYBdhLWcg3wf58G c) 我的情况: @Column(name="idx") String idx; @Formula("COALESCE(TO_NUMBER(REGEXP_SUBSTR(idx, '^\\d+')), 0)") @NotAudited Long idxNumber; - Krzysiek

2

我认为你可以尝试使用Spring Data的JpaSort类,它允许函数调用。

文档所述,你将会得到以下内容:

@Query("select u from User u where u.lastname like ?1%")
  List<User> findByAndSort(String lastname, Sort sort);

repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)"));

您还可以将其与Pageable对象一起使用。


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