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

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

Часто в процессе разработки конфигураций на платформе 1С возникает специфическая задача: необходимо отсортировать строки табличной части (ТЧ) документа не по ее прямым колонкам, а по полям-реквизитам ссылочных объектов. Классический пример — сортировка списка товаров в документе по артикулу, коду номенклатуры, производителю или виду свойства. Проблема заключается в том, что стандартные методы платформы запрещают прямую сортировку по полям, чей путь к данным является реквизитом поля табличной части. Это логичное архитектурное ограничение, но бизнес-логика требует решения.

Разберем вместе несколько проверенных подходов к решению этой задачи. Мы проанализируем как программные обходные пути с использованием таблиц значений и запросов, так и методы работы с интерфейсом и вспомогательными колонками.

Способ 1: Использование таблицы значений и запроса

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

Сначала мы выгружаем данные в таблицу значений методом Выгрузить(). Важное уточнение, которое часто вызывает сомнения: если вы используете конструкцию вида Объект.ИмяТабличнойЧасти.Выгрузить(), а затем Объект.ИмяТабличнойЧасти.Загрузить(), то значения специфических реквизитов формы, привязанных к ТЧ, не пропадают (если они не содержат сложных несериализуемых типов).

Посмотрим на примерный алгоритм реализации:

  1. Выгружаем табличную часть в таблицу значений.
  2. Помещаем эту таблицу в запрос как виртуальную таблицу.
  3. Соединяем её с нужными справочниками (например, Справочник.Номенклатура), чтобы вытащить артикул.
  4. Выполняем сортировку прямо внутри текста запроса с помощью оператора УПОРЯДОЧИТЬ ПО.
  5. Выгружаем результат запроса и загружаем обратно в ТЧ.

Пример программного кода:


ТЗ = Объект.Товары.Выгрузить();

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ТаблицаТовары.Номенклатура КАК Номенклатура,
    |    ТаблицаТовары.Количество КАК Количество,
    |    ТаблицаТовары.Цена КАК Цена
    |ПОМЕСТИТЬ ВТ_Товары
    |ИЗ
    |    &ТЗ КАК ТаблицаТовары
    |;
    |
    |ВЫБРАТЬ
    |    ВТ_Товары.Номенклатура КАК Номенклатура,
    |    ВТ_Товары.Количество КАК Количество,
    |    ВТ_Товары.Цена КАК Цена
    |ИЗ
    |    ВТ_Товары КАК ВТ_Товары
    |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК НоменклатураДанные
    |    ПО ВТ_Товары.Номенклатура = НоменклатураДанные.Ссылка
    |
    |УПОРЯДОЧИТЬ ПО
    |    НоменклатураДанные.Артикул ВОЗР";

Запрос.УстановитьПараметр("ТЗ", ТЗ);
Результат = Запрос.Выполнить().Выгрузить();

Объект.Товары.Загрузить(Результат);

Важный нюанс интерфейса: потеря фокуса (текущей строки)

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

Способ 2: Заполнение дополнительных колонок в цикле

Если табличная часть документа обычно содержит небольшое количество строк, можно обойтись без тяжелого механизма запросов. Мы можем программно добавить служебную колонку прямо в таблицу значений, заполнить её в цикле и применить стандартную сортировку платформы.

Рассмотрим по шагам этот подход:


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

// Обойдем таблицу обычным циклом
Для Каждого Стр Из ТЗ Цикл
    Стр.АртикулСортировка = Стр.Номенклатура.Артикул;
КонецЦикла;

// Выполняем сортировку
ТЗ.Сортировать("АртикулСортировка");

Объект.Товары.Загрузить(ТЗ);

Сложная множественная сортировка

Этот подход также позволяет гибко настраивать сортировку сразу по нескольким параметрам. Метод Сортировать() принимает строковый параметр, в котором колонки можно перечислить через запятую, явно указывая направление. Например: ТЗ.Сортировать("ГруппаНоменклатуры ВОЗР, Производитель ВОЗР, АртикулСортировка УБЫВ").

Особенности производительности и объект СравнениеЗначений

Проанализируем ситуацию, если мы захотим сортировать не по строковому артикулу, а по колонке, содержащей сами ссылки. Помните: когда платформа выполняет сортировку таблицы значений по ссылочным полям, она неявно обращается к базе данных для каждой строки, чтобы получить представление этой ссылки. На больших объемах это вызывает серьезные «тормоза». Если сортировка по ссылке всё же необходима, в метод нужно передавать специальный объект: Новый СравнениеЗначений.

Способ 3: Вспомогательные колонки и реквизиты формы

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

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

Главный недостаток этого метода — необходимость постоянной актуализации данных. Если пользователь выбирает или меняет номенклатуру, система должна сгенерировать событие ПриИзменении и перезаписать значение вспомогательной колонки «Артикул» для этой строки. Это создает дополнительный код поддержки.

Подведение итогов: что выбрать?

Выбор метода зависит от сценария использования:

  1. Если сортировка выполняется один раз при проведении или нажатии специальной кнопки («Отсортировать по артикулу») — оптимально использовать выгрузку в таблицу значений и сортировку через Запрос (Способ 1). Это работает быстро, надежно и меняется парой строк кода.
  2. Если объем данных в документе очень мал (до 100 строк), можно применить Способ 2 с добавлением программной колонки и заполнением ее в цикле. Это проще в написании.
  3. Если сортировка требуется постоянно в процессе редактирования документа пользователем (интерактивные клики по заголовкам), правильнее будет завести вспомогательные колонки-реквизиты и обновлять их обработчиками событий.

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

← На главную