3.5.3.4.5. Специализированная сортировка
Сортировка таблиц по атрибутам сущности в UI производится объектом типа CollectionContainerSorter
, который устанавливается для CollectionContainer. Стандартная реализация сортирует данные в памяти, если загруженный список умещается на одну страницу, или посылает запрос с соответствующим "order by" в базу данных. Выражение "order by" формируется бином JpqlSortExpressionProvider
среднего слоя.
Некоторые атрибуты могут потребовать специальной реализации сортировки. Ниже рассматривается простой пример: предположим, в сущности Foo
есть атрибут number
типа String
, но на самом деле атрибут хранит только числовые значения. Поэтому необходимо иметь порядок сортировки для чисел: 1, 2, 3, 10, 11
. Стандартный механизм сортировки в данном случае выдаст порядок 1, 10, 11, 2, 3
.
Сначала создайте наследника класса CollectionContainerSorter
в модуле web
для сортировки в памяти:
package com.company.demo.web;
import com.company.demo.entity.Foo;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.Sort;
import com.haulmont.cuba.gui.model.BaseCollectionLoader;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.impl.CollectionContainerSorter;
import com.haulmont.cuba.gui.model.impl.EntityValuesComparator;
import javax.annotation.Nullable;
import java.util.Comparator;
import java.util.Objects;
public class CustomCollectionContainerSorter extends CollectionContainerSorter {
public CustomCollectionContainerSorter(CollectionContainer container,
@Nullable BaseCollectionLoader loader) {
super(container, loader);
}
@Override
protected Comparator<? extends Entity> createComparator(Sort sort, MetaClass metaClass) {
MetaPropertyPath metaPropertyPath = Objects.requireNonNull(
metaClass.getPropertyPath(sort.getOrders().get(0).getProperty()));
if (metaPropertyPath.getMetaClass().getJavaClass().equals(Foo.class)
&& "number".equals(metaPropertyPath.toPathString())) {
boolean isAsc = sort.getOrders().get(0).getDirection() == Sort.Direction.ASC;
return Comparator.comparing(
(Foo e) -> e.getNumber() == null ? null : Integer.valueOf(e.getNumber()),
EntityValuesComparator.asc(isAsc));
}
return super.createComparator(sort, metaClass);
}
}
Если специализированная сортировка нужна только в некоторых экранах, CustomCollectionContainerSorter
можно инстанциировать прямо в экране:
public class FooBrowse extends StandardLookup<Foo> {
@Inject
private CollectionContainer<Foo> fooDc;
@Inject
private CollectionLoader<Foo> fooDl;
@Subscribe
private void onInit(InitEvent event) {
CustomCollectionContainerSorter sorter = new CustomCollectionContainerSorter(fooDc, fooDl);
fooDc.setSorter(sorter);
}
}
Если же специализированная сортировка должна являться глобальной, то создайте собственную фабрику, которая будет инстанциировать сортировщик для всей системы:
package com.company.demo.web;
import com.haulmont.cuba.gui.model.*;
import javax.annotation.Nullable;
public class CustomSorterFactory extends SorterFactory {
@Override
public Sorter createCollectionContainerSorter(CollectionContainer container,
@Nullable BaseCollectionLoader loader) {
return new CustomCollectionContainerSorter(container, loader);
}
}
Зарегистрируйте фабрику в web-spring.xml
для того, чтобы переопределить стандартную фабрику:
<bean id="cuba_SorterFactory" class="com.company.demo.web.CustomSorterFactory"/>
Теперь создайте собственную реализацию JpqlSortExpressionProvider
в модуле core
для сортировки на уровне БД:
package com.company.demo.core;
import com.company.demo.entity.Foo;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.core.app.DefaultJpqlSortExpressionProvider;
public class CustomSortExpressionProvider extends DefaultJpqlSortExpressionProvider {
@Override
public String getDatatypeSortExpression(MetaPropertyPath metaPropertyPath, boolean sortDirectionAsc) {
if (metaPropertyPath.getMetaClass().getJavaClass().equals(Foo.class)
&& "number".equals(metaPropertyPath.toPathString())) {
return String.format("CAST({E}.%s BIGINT)", metaPropertyPath.toString());
}
return String.format("{E}.%s", metaPropertyPath.toString());
}
}
Зарегистрируйте класс в spring.xml
для того, чтобы переопределить стандартную реализацию поставщика выражений:
<bean id="cuba_JpqlSortExpressionProvider" class="com.company.demo.core.CustomSortExpressionProvider"/>