【问题标题】:How to sort PageRequest on String as numeric value如何将字符串上的 PageRequest 排序为数值
【发布时间】:2016-11-09 13:30:16
【问题描述】:

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

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 数字中的字符值进行排序?

【问题讨论】:

  • 你有解决这个问题的办法吗?

标签: java spring spring-data-jpa


【解决方案1】:

所以基本上你需要做两件事:

  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);

【讨论】:

  • 我不确定这是否是我想要的。 PageRequest 可以对对象的总列表进行分页响应。这可能意味着我只有 200 个对象中的 10 个可用。我不确定如何在这里适合您的解决方案。对我来说,这里似乎是后排序。我将看看如何适应这个解决方案并报告它的作用。
  • 我正在使用Page&lt;House&gt; houses = this.houseRepository.findAll(request); 那么我应该在哪里使用这个比较器呢?
  • 你用什么数据库?
  • 我使用 Postgres 数据库。
【解决方案2】:

我认为您可以尝试允许函数调用的 Spring Data JpaSort 类。

documentation 中所述,您将拥有类似的内容:

@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 对象一起使用。

【讨论】:

    【解决方案3】:

    假设您有一个提交了 String 的实体,并且您希望使用 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");
     }
    

    【讨论】:

    • 我认为这个解决方案是最好的,但我这边有一个小更新:a) 当你将@Formula 放在字段声明周围时,它看起来会更好(不需要放置它在 getter b) 上,当您收到“当前不支持公式映射”之类的错误时,您可能需要添加 @NotAudited 注释(更多信息:stackoverflow.com/questions/44327871/… c)我的情况:`@Column(name="idx​​")字符串 idx; @Formula("COALESCE(TO_NUMBER(REGEXP_SUBSTR(idx, '^\\d+')), 0)") @NotAudited Long idxNumber; `
    猜你喜欢
    • 2016-10-01
    • 2010-11-18
    • 2018-12-27
    • 1970-01-01
    • 2015-09-28
    • 2012-01-20
    • 2021-11-22
    • 2011-02-10
    • 1970-01-01
    相关资源
    最近更新 更多