Сортировка по нескольким параметрам через JpqlSortExpressionProvider

Есть некоторая сущность со строковым атрибутом number, который представляет из себя некоторым образом конкатинированную дату и номер.

public class CheckRequest {
    @NotNull
    @Column(name = "NUMBER_", nullable = false)
    private String number; // значению вида mm_yy_xxx, например, 02_12_001.
}

При выводе в таблицу необходимо сортировать по этому атрибуту некоторым образом разобрав строку.
Пытаюсь сделать это расширив DefaultJpqlSortExpressionProvider (тут в качетстве сортируемой сущности выступает CheckRequestStuff у которой есть ассоциация на CheckRequest):

public class CustomSortExpressionProvider extends DefaultJpqlSortExpressionProvider {

    @Nonnull
    @Override
    public String getDatatypeSortExpression(MetaPropertyPath metaPropertyPath, boolean sortDirectionAsc) {
        final Class<Object> javaClass = metaPropertyPath.getMetaClass().getJavaClass();
        final String propertyPath = metaPropertyPath.toPathString();
        final String sortDirection = sortDirectionAsc ? "ASC" : "DESC";

        if (javaClass.equals(CheckRequestStuff.class) && "request.number".equals(propertyPath)) {
            return String.format(
                    "CAST(SUBSTRING({E}.%1$s, 4, 2) BIGINT) %2$s, CAST(SUBSTRING({E}.%1$s, 1, 2) BIGINT) %2$s, CAST(SUBSTRING({E}.%1$s, 7) BIGINT) %2$s",
                    metaPropertyPath,
                    sortDirection
            );
        }

        return String.format("{E}.%s", metaPropertyPath);
    }

}

Но это не работает.
Если дебагером посмотреть во что в итоге “превращается” JPQL, то видно, что в QueryTransformerAstBased после parseOrderByItem(expression) от изначального выражения остаётся только первая часть, до запятой CAST(SUBSTRING(e.number, 4, 2) BIGINT).

jmix_sort_expr

В итоге сортировка отрабатывает, но только по одному оставшемуся выражению.

Вопрос. Через JpqlSortExpressionProvider нет возможности задать сортировку по нескольким параметрам? или это как-то по другому нужно записывать, синтаксис может особый какой-то? Или это, всё таки, баг?

JMIX 1.5.5

Подобная проблема тянется из CUBA, потому что используется один и тот же парсер. Я там тоже задал подобный вопрос (Сортировка по нескольким property через JpqlSortExpressionProvider - Вопросы и проблемы - CUBA.Platform), но немного с другими входными данными. Ответа так и не дождался, никакого. А хотелось бы.

Евгений, здравствуйте!

От реализация метода io.jmix.data.persistence.JpqlSortExpressionProvider#getDatatypeSortExpression ожидалось возвращение единственного выражения для сортировки, а не набора нескольких выражений. В соответствии с этим и работает логика в QueryTransformerAstBased, отбрасывая все лишнее после запятой.
Однако, я думаю, можно сделать и так, чтобы можно было возвращать несколько значений. Завел для этого issue. Спасибо за то, что обратили внимание на такой способ применения этого метода!

В качестве воркэраунда, могу предложить несколько вариантов:

  1. Переопределить io.jmix.data.impl.jpql.generator.SortJpqlGenerator#getPropertySortExpressions():134 и попробовать возвращать не Collections.singletonMap(sortExpression, sortDirection), а перед этим разбить sortExpression на несколько выражений по , и сложить их в map по отдельности. Так же лучше не добавлять asc/desc в конце строки, а положить нужный Sort.Direction в возвращаемый map, направление будет добавлено позже автоматически.
  2. Написать более хитрое преобразование, которое возвращает одну строку для сортировки, преобразованную так, чтобы не требовалось несколько выражений. (Если я правильно понимаю, что сортировка идет в одном и том же направлении, то почему бы эти substring не склеить друг с другом?)
  3. Хранить строку так, чтобы ее можно было сортировать одним выражением.
  4. Декомпозировать/денормализовать этот атрибут разбив на/добавив другие атрибуты так, чтобы каждый из них требовал только одного выражения для сортировки.

С уважением,
Дмитрий

Спасибо за ответ!
Даже у нас данный случай такой “сложной” сортировки не единственный, поэтому думаю подобный кейс может быть интересен и другим разработчикам. Если получится реализовать логику сортировки по нескольким выражениям, будет классно!

Спасибо за предложенные варианты! В данном случае самым простым и рабочим оказался второй. Сам не догадался :grinning:

1 симпатия