Сортировка списков

Достаточно часто перед разработчиком стоит задача по сортировке коллекций. Это может быть список клиентов в алфавитном порядке или прайс-лист продукции, упорядоченный по цене. В этой статье рассмотрим варианты сортировки, которые предлагает фреймворк FBA Toolkit, а также покажем, как можно реализовать свой вариант упорядочивания.

Сортировка записей запроса

Пожалуй, самым оптимальным по производительности вариантом будет выполнение сортировки непосредственно при выборке данных из базы, используя SQL-синтаксис.

а) Менеджеры данных (классы RowDao и его наследники)  реализуют функции select и selectCursor в которые дополнительным параметром могут быт переданы условия сортировки:

1
2
3
4
5
6
7
8
9
10
11
12
/*
 * Выбрать все записи из справочника (не установлен отбор первым параметром)
 * отсортированные по наименованию
 */
return dao.select(null, CatalogNomenklatura.FIELD_NAME_DESCRIPTION);
 
/*
 * Отбор по родителю, сортировка – группы сверху
 */
return dao.select(parent, null, null,
            CatalogNomenklatura.FIELD_NAME_LEVEL + ", "
                        + CatalogNomenklatura.FIELD_NAME_FOLDER + " DESC");
/*
 * Выбрать все записи из справочника (не установлен отбор первым параметром)
 * отсортированные по наименованию
 */
return dao.select(null, CatalogNomenklatura.FIELD_NAME_DESCRIPTION);

/*
 * Отбор по родителю, сортировка – группы сверху
 */
return dao.select(parent, null, null,
          	CatalogNomenklatura.FIELD_NAME_LEVEL + ", "
                       	+ CatalogNomenklatura.FIELD_NAME_FOLDER + " DESC");

б) Так же вы можете использовать построитель запроса OrmLite:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CatalogNomenklaturaDao extends CatalogDao<CatalogNomenklatura> {
 
        /*
         * Пример указания сортировки с помощью построителя запроса OrmLite:
         * помеченные на удаление элементы будут внизу списка
         */
        public List<CatalogNomenklatura> selectBuilderRaw() throws SQLException {
                QueryBuilder<CatalogNomenklatura, String> builder = queryBuilder();
                builder.orderByRaw(CatalogNomenklatura.FIELD_NAME_DELETIONMARK
                                + " DESC");
                return query(builder.prepare());
        }
}
public class CatalogNomenklaturaDao extends CatalogDao<CatalogNomenklatura> {

    	/*
    	 * Пример указания сортировки с помощью построителя запроса OrmLite:
    	 * помеченные на удаление элементы будут внизу списка
    	 */
    	public List<CatalogNomenklatura> selectBuilderRaw() throws SQLException {
            	QueryBuilder<CatalogNomenklatura, String> builder = queryBuilder();
            	builder.orderByRaw(CatalogNomenklatura.FIELD_NAME_DELETIONMARK
                            	+ " DESC");
            	return query(builder.prepare());
    	}
}

в)  и  ручное составлением инструкций SQL на выборку данных с указанием сортировки. Этот вариант самый гибкий, но и самый сложный при этом.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public List<CatalogNomenklatura> selectRaw() throws SQLException {
 
        //Составление текста запроса: выборка только необходимых полей и указание сортировки
        StringBuilder sb = new StringBuilder();
        sb.append(" SELECT ")
          .append(CatalogNomenklatura.FIELD_NAME_REF).append(",")
          .append(CatalogNomenklatura.FIELD_NAME_CODE).append(",")
          .append(CatalogNomenklatura.FIELD_NAME_DESCRIPTION);
        sb.append(" FROM ").append(CatalogNomenklatura.TABLE_NAME);
        sb.append(" ORDER BY ")
          .append(CatalogNomenklatura.FIELD_NAME_DESCRIPTION + " DESC");
 
        //Выборка данных с преобразованием результата  к коллекции объектов
        GenericRawResults<CatalogNomenklatura> rawResults = queryRaw(
                        sb.toString(), new RawRowMapper<CatalogNomenklatura>() {
 
                         @Override
                         public CatalogNomenklatura mapRow(String[] columnNames,
                                String[] resultColumns) throws SQLException {
 
                                CatalogNomenklatura item = new CatalogNomenklatura();
                                item.setRef(UUID.fromString(resultColumns[0]));
                                item.setCode(resultColumns[1]);
                                item.setDescription(resultColumns[2]);
                                return item;
                        }
                });
 
        //результат выборки как список
        return rawResults.getResults();
}
public List<CatalogNomenklatura> selectRaw() throws SQLException {

    	//Составление текста запроса: выборка только необходимых полей и указание сортировки
    	StringBuilder sb = new StringBuilder();
    	sb.append(" SELECT ")
          .append(CatalogNomenklatura.FIELD_NAME_REF).append(",")
          .append(CatalogNomenklatura.FIELD_NAME_CODE).append(",")
          .append(CatalogNomenklatura.FIELD_NAME_DESCRIPTION);
    	sb.append(" FROM ").append(CatalogNomenklatura.TABLE_NAME);
    	sb.append(" ORDER BY ")
          .append(CatalogNomenklatura.FIELD_NAME_DESCRIPTION + " DESC");

    	//Выборка данных с преобразованием результата  к коллекции объектов
    	GenericRawResults<CatalogNomenklatura> rawResults = queryRaw(
    	            	sb.toString(), new RawRowMapper<CatalogNomenklatura>() {

    	                 @Override
    	                 public CatalogNomenklatura mapRow(String[] columnNames,
    	                       	String[] resultColumns) throws SQLException {

    	                      	CatalogNomenklatura item = new CatalogNomenklatura();
    	                       	item.setRef(UUID.fromString(resultColumns[0]));
    	                       	item.setCode(resultColumns[1]);
    	                       	item.setDescription(resultColumns[2]);
                                return item;
                        }
             	});

    	//результат выборки как список
    	return rawResults.getResults();
}

Сортировка списков объектов

Этот вариант сортировки может быть использован, кода данные уже считаны из базы и хранятся в коллекции List. Естественно этот вариант не применим для курсоров (selectCursor).

а) Начиная с версии 1.0.4, FBA Toolkit содержит встроенные методы сортировки:
- справочников по представлению;
- документов по дате

Теперь вы можете отсортировать коллекцию в одну строчку:

1
Collections.sort(<ваш список>);
Collections.sort(<ваш список>);

Например, сортировка справочника по представлению:

1
2
List<CatalogNomenklatura> lst = <выборка из базы>;
Collections.sort(lst);
List<CatalogNomenklatura> lst = <выборка из базы>;
Collections.sort(lst);

    

Направление сортировки будет зависеть от реализации метода getPresentation данного справочника:

1
2
3
4
5
6
7
public class CatalogNomenklatura extends Catalog {
 
    @Override
    public String getPresentation() {
            return getCode();
    }
}
public class CatalogNomenklatura extends Catalog {

   	@Override
   	public String getPresentation() {
          	return getCode();
   	}
}

Например, если основное представление элементов справочника в виде кода, то и сортировка будет по коду.

б)  и наконец, вы можете создать свои правила сортировки  с помощью интерфейса Comparatoг, например так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class ExTableCeniDao extends TableExDao<ExTableCeni> {
 
        /**
         * Возвращает прайс-лист отсортированный по цене и представлению номенклатуры
         * @param type тип цены
         * @return
         * @throws SQLException
         */
        public List<ExTableCeni> getPriceOfType(CatalogTipiCenNomenklaturi type) throws SQLException{
 
                HashMap<String,Object> filter = new HashMap<String, Object>();
                filter.put(ExTableCeni.FIELD_NAME_TIP_CEN, type);
 
                List<ExTableCeni> data = select(filter);
                Collections.sort(data, sortedByPrice);
                return data;
        }
 
        /*
         * Сортировка по цене и представлению номенклатуры
         */
        private Comparator<ExTableCeni> sortedByPrice = new Comparator<ExTableCeni>() {
 
                @Override
                public int compare(ExTableCeni lhs, ExTableCeni rhs) {
                        if (lhs.cena > rhs.cena)
                                return 1;
                        else if (lhs.cena < rhs.cena)
                                return -1;
                        else if (CatalogNomenklatura.isEmpty(lhs.nomenklatura))
                                return -1;
                        else
                                return lhs.nomenklatura.compareTo(rhs.nomenklatura);
                }
 
        };
}
public class ExTableCeniDao extends TableExDao<ExTableCeni> {

    	/**
    	 * Возвращает прайс-лист отсортированный по цене и представлению номенклатуры
    	 * @param type тип цены
    	 * @return
    	 * @throws SQLException
    	 */
    	public List<ExTableCeni> getPriceOfType(CatalogTipiCenNomenklaturi type) throws SQLException{

            	HashMap<String,Object> filter = new HashMap<String, Object>();
            	filter.put(ExTableCeni.FIELD_NAME_TIP_CEN, type);

            	List<ExTableCeni> data = select(filter);
            	Collections.sort(data, sortedByPrice);
            	return data;
    	}

    	/*
    	 * Сортировка по цене и представлению номенклатуры
    	 */
    	private Comparator<ExTableCeni> sortedByPrice = new Comparator<ExTableCeni>() {

            	@Override
            	public int compare(ExTableCeni lhs, ExTableCeni rhs) {
                    	if (lhs.cena > rhs.cena)
                            	return 1;
                    	else if (lhs.cena < rhs.cena)
                            	return -1;
                    	else if (CatalogNomenklatura.isEmpty(lhs.nomenklatura))
                            	return -1;
                    	else
                            	return lhs.nomenklatura.compareTo(rhs.nomenklatura);
            	}

    	};
}

Метод getPriceOfType DAO-менеджера для внешней таблицы «Цены» возвращает коллекцию отсортированную по цене. Если цена одинаковая, сортировка выполняется по представлению номенклатуры. Результат сортировки:

Полностью исходный код по этой статье смотрите в примере “Заказ покупателя” в SVN-репоритории https://xp-dev.com/svn/fba_toolkit_public/samples/fbaSample3Order/. Переключитесь на соответствующую ревизию (ориентируйтесь по комментарию).

Если у вас есть вопросы или комментарии, используйте форму «Контакты» для связи.

Похожие записи: