Tri de l'expression dans Spring Data JPA

Sep 17 2020

J'ai la classe d'entité suivante où objectId est une chaîne alphanumérique

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

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

J'ai aussi le référentiel suivant

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

Maintenant, quand je fais une requête basée sur la spécification et des objets paginables comme celui-ci

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

Je veux être en mesure de trier le résultat en fonction de CaseInfo.objectId numériquement afin que l'ordre par requête SQL ressemble à quelque chose comme ça

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

Si je fais quelque chose comme

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

il trie par ordre alphabétique de sorte que "100" soit avant "2", ce qui est faux pour mon cas d'utilisation.

j'ai trouvé https://www.baeldung.com/spring-data-jpa-query où il utilise

JpaSort.unsafe("LENGTH(name)")

mais cela ne semble pas fonctionner car si je le fais

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

Il donne le message d'erreur "Aucune propriété à trouver pour le type CaseInfo! Vouliez-vous dire 'id'?"

Quelqu'un connaît-il un moyen de donner une expression personnalisée à l'objet Sort?

Réponses

3 AlexRudenko Sep 18 2020 at 02:02

Vous pouvez ajouter un champ de formule convertissant la valeur de chaîne en valeur numérique, puis trier par ce champ ou utiliser l'implémentation par défaut 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;
}

Dépôt:

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

    // sort by formula field 
    List<CaseInfo> findAllByOrderByNumObjectId(Pageable pageable);
}

Il y a un truc avec l' aide de CASTfonction@Formula - il est très probable à l' échec lors de la coulée à INT, INTEGER, BIGINTmais il fonctionne lors de la coulée à NUMERIC(10, 0).

Numeric doit également être suffisamment grand pour contenir la valeur dans la chaîne après la conversion, sinon un débordement d'entier peut se produire.