在Spring Data JPA中的排序表达式

huangapple go评论99阅读模式
英文:

Sorting expression in spring data JPA

问题

我有以下的实体类,其中 objectId 是字母数字字符串:

@Data
@Entity
@Table(name = "CASE_INFO")
public class CaseInfo {
  @Id
  @Column(name = "ID")
  private UUID id;

  @Column(name = "OBJECT_ID")
  private String objectId;
}

我还有以下的仓库:

@Repository
public interface CaseInfoRepository extends JpaRepository<CaseInfo, UUID>, JpaSpecificationExecutor<CaseInfo> { }

现在,当我基于 Specification 和 Pageable 对象进行查询时,代码如下:

Specification<CaseInfo> specification = (root, query, criteriaBuilder) -> criteriaBuilder.and();
Pageable pageable = PageRequest.of(0, 25, Sort.by("objectId"));
caseInfoRepository.findAll(specification, pageable);

我想要根据 CaseInfo.objectId 的数值进行排序,这样 SQL 查询中的 order by 子句会类似于:

... order by to_number(OBJECT_ID) ...

如果我尝试像这样做:

PageRequest.of(0, 25, Sort.by("objectId"))

它会按字母顺序排序,所以 "100" 会在 "2" 前面,这对我的用例来说是错误的。

我在 https://www.baeldung.com/spring-data-jpa-query 找到了一个方法,它使用了:

JpaSort.unsafe("LENGTH(name)")

但是这似乎不起作用,因为如果我这样做:

PageRequest.of(0, 25, JpaSort.unsafe("to_number(objectId)"))

会得到错误信息 "No property to found for type CaseInfo! Did you mean 'id'?"。

有谁知道如何为 Sort 对象提供自定义表达式?

英文:

I have the following entity class where objectId is alphanumeric string

@Data
@Entity
@Table(name = &quot;CASE_INFO&quot;)
public class CaseInfo {
  @Id
  @Column(name = &quot;ID&quot;)
  private UUID id;

  @Column(name = &quot;OBJECT_ID&quot;)
  private String objectId;
}

I also have the following repository

@Repository
public interface CaseInfoRepository extends JpaRepository&lt;CaseInfo, UUID&gt;, JpaSpecificationExecutor&lt;CaseInfo&gt; { }

Now when I make a query based on Specification and Pageable objects like this

Specification&lt;CaseInfo&gt; specification = (Specification&lt;CaseInfo&gt;) (root, query, criteriaBuilder) -&gt; criteriaBuilder.and();
Pageable pageable = PageRequest.of(0, 25, Sort.by(&quot;objectId&quot;));
caseInfoRepository.findAll(specification, pageable);

I want to be able to sort result based on CaseInfo.objectId numerically so that the order by in sql query would look something like this

... order by to_number(OBJECT_ID) ...

If I do something like

PageRequest.of(0, 25, Sort.by(&quot;objectId&quot;))

it orders alphabetically so that "100" is before "2" which is wrong for my use case.

I found https://www.baeldung.com/spring-data-jpa-query where it uses

JpaSort.unsafe(&quot;LENGTH(name)&quot;)

but this does not seem to work because if I do

PageRequest.of(0, 25, JpaSort.unsafe(&quot;to_number(objectId)&quot;))

It gives error message "No property to found for type CaseInfo! Did you mean 'id'?"

Does anybody know a way to give custom expression to Sort object?

答案1

得分: 4

你可以添加一个公式字段,将字符串值转换为数值,并根据此字段进行排序,或者使用默认的实现findAll(Pageable pageable)

@Data
@Entity
@Table(name = "CASE_INFO")
public class CaseInfo {
  @Id
  @Column(name = "ID")
  private UUID id;

  @Column(name = "OBJECT_ID")
  private String objectId;

  @Formula(value = "CAST(OBJECT_ID AS NUMERIC(10, 0))")
  private int numObjectId;
}

Repository:

@Repository
public interface CaseInfoRepository extends 
                 JpaRepository<CaseInfo, UUID>, JpaSpecificationExecutor<CaseInfo> {

    // 按公式字段排序
    List<CaseInfo> findAllByOrderByNumObjectId(Pageable pageable);
}

在使用@Formula中的CAST函数时有一个技巧,很可能在将其转换为INTINTEGERBIGINT时会失败,但是将其转换为NUMERIC(10, 0)时可以正常工作。

NUMERIC的范围应足够大,能够容纳转换后字符串中的值,否则可能会导致整数溢出。

英文:

You could add a formula field casting the string value to the numeric one and then sort by this field or use default implementation findAll(Pageable pageable):

@Data
@Entity
@Table(name = &quot;CASE_INFO&quot;)
public class CaseInfo {
  @Id
  @Column(name = &quot;ID&quot;)
  private UUID id;

  @Column(name = &quot;OBJECT_ID&quot;)
  private String objectId;

  @Formula(value = &quot;CAST(OBJECT_ID AS NUMERIC(10, 0))&quot;)
  private int numObjectId;
}

Repository:

@Repository
public interface CaseInfoRepository extends 
                 JpaRepository&lt;CaseInfo, UUID&gt;, JpaSpecificationExecutor&lt;CaseInfo&gt; {

    // sort by formula field 
    List&lt;CaseInfo&gt; findAllByOrderByNumObjectId(Pageable pageable);
}

There is a trick with using CAST function in @Formula -- it is very likely to fail when casting to INT, INTEGER, BIGINT but it works when casting to NUMERIC(10, 0).

Numeric also should be large enough to contain the value within the string after cast otherwise an integer overflow may occur.

huangapple
  • 本文由 发表于 2020年9月17日 21:56:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/63939687.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定