Как реализовать свою сортировку в форме списка справочника 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов в 1С:Предприятие часто возникает классическая задача: настроить нестандартную сортировку элементов в списке справочника. Типичный пример — так называемая «естественная» (алфавитно-цифровая) сортировка. По умолчанию платформа сортирует строки посимвольно. Из-за этого код А-10 в списке отображается выше (раньше), чем код А-2, поскольку символ «1» идет раньше символа «2». Чтобы исправить это поведение и добиться порядка А-2, А-10, стандартных средств упорядочивания по возрастанию или убыванию становится недостаточно.

В этой статье мы подробно разберем, почему стандартные механизмы накладывают такие ограничения, проанализируем различные подходы к решению этой задачи в обычных формах (толстый клиент) и рассмотрим наиболее эффективный и промышленный метод решения проблемы — метод нормализованного индекса, а также альтернативные варианты.

Почему стандартный СправочникСписок не поддерживает произвольную сортировку?

Выясним причину, по которой мы не можем просто взять и написать произвольный SQL-запрос с конструкцией ORDER BY SUBSTRING... для отображения данных в стандартной форме списка. Объект СправочникСписок в обычных формах напрямую связан с таблицами СУБД. Чтобы обеспечить моментальное пролистывание списков, содержащих миллионы элементов, и моментальный поиск «по первым символам» (как это было реализовано еще в 1С 7.7), платформа использует механизм динамической выборки порций данных.

Эта выборка жестко опирается на существующие индексы таблиц в базе данных. Платформа 1С не выполняет чтение всей таблицы в память клиента; она запрашивает лишь видимую часть строк. Любая попытка навязать СУБД сортировку по вычисляемому на лету полю (например, с использованием функций substring или регулярных выражений) заставит СУБД отказаться от использования индексов и выполнить полное сканирование таблицы (Table Scan). Для больших баз данных это приведет к моментальному зависанию интерфейса и колоссальной нагрузке на сервер.

Именно поэтому сортировка в объекте СправочникСписок доступна только по тем реквизитам, у которых в конфигураторе свойство «Индексировать» установлено в значение «Индексировать» или «Индексировать с дополнительным упорядочиванием».

Основное решение: Метод «нормализованного (служебного) индекса»

Рассмотрим самый надежный, быстрый и производительный способ решения проблемы. Раз мы не можем сортировать данные «на лету» в запросе СУБД, мы должны подготовить данные к сортировке заранее — в момент их записи в базу данных. Этот паттерн называется нормализацией ключа сортировки.

Идея заключается в том, что мы создаем дополнительный скрытый реквизит, в котором будет храниться преобразованный («нормализованный») код элемента. Например, код А-2 преобразуется в А-000002, а код А-10 — в А-000010. При посимвольном сравнении таких нормализованных строк СУБД выстроит их в абсолютно правильном математическом порядке.

Разберем по шагам, как внедрить это решение в конфигурацию:

  1. Создание реквизита. В конфигураторе откройте нужный справочник и добавьте новый реквизит. Назовем его ИндексСортировки (тип — Строка, длина должна быть достаточной для хранения преобразованного кода, например, 50 символов).
  2. Включение индексирования. В свойствах реквизита ИндексСортировки обязательно установите значение свойства «Индексировать» (или «Индексировать с дополнительным упорядочиванием»). Это ключевой шаг, без которого быстрая сортировка в списке работать не будет.
  3. Автоматическое заполнение при записи. Перейдем в модуль объекта справочника и напишем алгоритм, который будет формировать значение этого индекса при записи элемента. Разберем пример кода для обработчика ПередЗаписью:

Процедура ПередЗаписью(Отказ)
    
    // Исключаем работу подписки или транзакций, если обмен данными загружается напрямую
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Вызываем функцию нормализации кода
    ИндексСортировки = ПолучитьНормализованныйКод(Код);
    
КонецПроцедуры

Функция ПолучитьНормализованныйКод(ИсходныйКод) Экспорт
    
    // Пример простой нормализации: находим числовую часть после дефиса и дополняем её нулями
    // Допустим, код имеет формат "Префикс-Номер" (например, "А-12")
    ПозицияРазделителя = Найти(ИсходныйКод, "-");
    Если ПозицияРазделителя > 0 Тогда
        Префикс = Лев(ИсходныйКод, ПозицияРазделителя);
        ЧисловаяЧасть = Сред(ИсходныйКод, ПозицияРазделителя + 1);
        
        // Дополняем числовую часть ведущими нулями до длины 6 символов
        Пока СтрДлина(ЧисловаяЧасть) < 6 Цикл
            ЧисловаяЧасть = "0" + ЧисловаяЧасть;
        КонецЦикла;
        
        Возврат Префикс + ЧисловаяЧасть;
    Иначе
        // Если разделитель не найден, возвращаем исходный код
        Возврат ИсходныйКод;
    EndIf;
    
КонецФункции

После реализации этого кода нам потребуется один раз запустить обработку для существующих элементов справочника, чтобы перезаписать их и заполнить новый реквизит ИндексСортировки.

  1. Подключение индекса к форме списка. Теперь настроим форму списка нашего справочника так, чтобы она автоматически использовала новый порядок. В модуле формы списка (в событии ПриОткрытии) пропишем следующий код:

Процедура ПриОткрытии()
    
    // Разрешаем сортировку по нашему новому служебному реквизиту
    Попытка
        ЭлементыФормы.СправочникСписок.НастройкаПорядка.ИндексСортировки.Доступность = Истина;
        
        // Устанавливаем сортировку по умолчанию
        СправочникСписок.Порядок.Установить("ИндексСортировки Возр");
    Исключение
        Сообщить("Не удалось установить пользовательский порядок сортировки: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Результат: Пользователи работают в привычном интерфейсе, видят красивый стандартный код А-2, но сама СУБД упорядочивает строки по скрытому индексированному полю ИндексСортировки. При этом полностью сохраняется производительность системы и стандартный быстрый поиск по первым символам.

Альтернативное решение: Использование «Таблицы значений» (ТЗ) на форме

Проанализируем альтернативный вариант, который часто упоминают разработчики (включая сообщения 8-10 на форуме): отказаться от стандартного объекта СправочникСписок, выгрузить все данные запросом в Таблицу Значений, отсортировать её программно методами встроенного языка 1С и вывести на форму через табличное поле.

Посмотрим на пример кода, реализующий этот подход при открытии формы:


Процедура ПриОткрытии()
    
    // Создаем запрос для получения данных
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Ссылка КАК Ссылка,
        |   Номенклатура.Код КАК Код,
        |   Номенклатура.Наименование КАК Наименование
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура";
    
    ТаблицаДанных = Запрос.Выполнить().Выгрузить();
    
    // Добавляем колонку для сортировки в ТЗ на клиенте
    ТаблицаДанных.Колонки.Добавить("КлючСортировки", Новый ОписаниеТипов("Строка"));
    
    Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
        // Заполняем ключ сортировки аналогично функции нормализации
        СтрокаДанных.КлючСортировки = ПолучитьНормализованныйКод(СтрокаДанных.Код);
    КонецЦикла;
    
    // Сортируем таблицу значений средствами встроенного языка
    ТаблицаДанных.Сортировать("КлючСортировки Возр");
    
    // Связываем полученную ТЗ с элементом управления на форме
    ЭлементыФормы.ТабличноеПолеДанных.Значение = ТаблицаДанных;
    ЭлементыФормы.ТабличноеПолеДанных.СоздатьКолонки();
    
КонецПроцедуры

Почему это плохое архитектурное решение для рабочих баз данных? Разберем ключевые недостатки:

Таким образом, использование Таблицы Значений оправдано исключительно в небольших, фиксированных по размеру справочниках (до 100-200 элементов), где производительность не играет роли.

Особенности реализации в Управляемых формах (Динамический список)

Если мы решим перевести форму на управляемую платформу (1С v8.3 Управляемое приложение), то стандартным элементом отображения списков становится ДинамическийСписок.

Здесь действительно появляется возможность включить свойство «Произвольный запрос» и написать собственный текст выборки данных. Однако, здесь тоже есть важные подводные камни, которые необходимо учитывать:

Поэтому даже на управляемых формах использование нормализованного индекса (дополнительного реквизита в объекте) признается единственным промышленным и верным с точки зрения производительности стандартом разработки.

← На главную