В процессе разработки часто возникает задача упорядочить строки в табличной части документа. Напрямую у объекта ТабличнаяЧасть отсутствует встроенный метод для автоматической сортировки данных по значениям колонок — платформа предоставляет только метод ручного перемещения строк Сдвинуть(). Поэтому классическим решением задачи является выгрузка данных в объект ТаблицаЗначений, последующая сортировка и обратная загрузка в табличную часть.
Разберем по шагам, как правильно создать таблицу значений с нужной структурой колонок, как выполнить стандартную сортировку и как обойти ограничение платформы при необходимости упорядочивания по реквизитам через точку (например, по свойствам номенклатуры).
Выясним причину, почему разработчику может потребоваться отдельная пустая таблица значений с типами колонок как у табличной части. Если необходимо получить структуру колонок без переноса самих строк, в платформе 1С предусмотрен специальный метод ВыгрузитьКолонки(). Рассмотрим пример:
// Создание пустой таблицы значений с полным набором и типами колонок ТЧ
ТЗ = ДокументОбъект.Запасы.ВыгрузитьКолонки();
Также пустую таблицу значений можно получить с помощью выгрузки с пустым массивом строк:
ТЗ = ДокументОбъект.Запасы.Выгрузить(Новый Массив);
Если же цель заключается именно в сортировке уже имеющихся строк табличной части, создавать пустую таблицу не требуется — достаточно вызвать метод Выгрузить() без параметров, который скопирует и структуру колонок, и все содержащиеся строки.
Рассмотрим стандартный сценарий, когда сортировка выполняется по колонкам, непосредственно входящим в состав табличной части (например, по реквизитам Номенклатура, Количество или Цена). Алгоритм состоит из трех действий:
Выгрузить().Сортировать().Загрузить().Посмотрим на пример программного кода:
// 1. Выгружаем данные табличной части в таблицу значений
ТЗ = ДокументОбъект.Запасы.Выгрузить();
// 2. Сортируем таблицу по нужным колонкам (например, по номенклатуре по возрастанию)
ТЗ.Сортировать("Номенклатура Возр");
// 3. Загружаем отсортированные строки обратно в табличную часть
ДокументОбъект.Запасы.Загрузить(ТЗ);
Проанализируем ситуацию, озвученную в обсуждении: что делать, если нужно выполнить сортировку по составному пути к реквизиту, например Номенклатура.НоменклатурнаяГруппа.Порядок? Метод Сортировать() у объекта ТаблицаЗначений не поддерживает разыменование полей через точку. Попытка передать строку "Номенклатура.НоменклатурнаяГруппа.Порядок" вызовет исключение времени выполнения, так как метод ожидает только имена реальных колонок текущей таблицы значений.
Для решения этой проблемы рассмотрим два эффективных подхода.
Разберем по шагам первый способ, который отлично подходит при небольшом количестве строк в табличной части:
ТаблицаЗначений.Колонки.Добавить().Загрузить(). Платформа 1С автоматически сопоставляет данные по именам колонок, поэтому лишняя колонка просто проигнорируется и удалять ее вручную необязательно.Посмотрим на пример реализации:
// Выгружаем табличную часть
ТЗ = ДокументОбъект.Запасы.Выгрузить();
// Добавляем вспомогательную колонку для числового порядка
ТЗ.Колонки.Добавить("ПорядокСортировки", Новый ОписаниеТипов("Число"));
// Заполняем вспомогательную колонку
Для Каждого СтрокаТЗ Из ТЗ Цикл
СтрокаТЗ.ПорядокСортировки = СтрокаТЗ.Номенклатура.НоменклатурнаяГруппа.Порядок;
КонецЦикла;
// Выполняем сортировку по вспомогательной колонке
ТЗ.Сортировать("ПорядокСортировки Возр");
// Загружаем данные обратно в табличную часть
ДокументОбъект.Запасы.Загрузить(ТЗ);
Если табличная часть содержит сотни или тысячи строк, обращение через точку в цикле приведет к множественным отдельным запросам к базе данных (проблема N+1). Проанализируем более производительный вариант с использованием объекта Запрос, где таблица значений передается в качестве источника временной таблицы:
ТЗ = ДокументОбъект.Запасы.Выгрузить();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ИсходнаяТЗ.*,
| ЕСТЬNULL(НоменклатурныеГруппы.Порядок, 0) КАК ПорядокСортировки
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
| &ТаблицаДанных КАК ИсходнаяТЗ
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО ИсходнаяТЗ.Номенклатура = Номенклатура.Ссылка
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НоменклатурныеГруппы КАК НоменклатурныеГруппы
| ПО Номенклатура.НоменклатурнаяГруппа = НоменклатурныеГруппы.Ссылка
|;
|
|ВЫБРАТЬ
| *
|ИЗ
| ВТ_Данные КАК ВТ_Данные
|УПОРЯДОЧИТЬ ПО
| ВТ_Данные.ПорядокСортировки ВОЗР";
Запрос.УстановитьПараметр("ТаблицаДанных", ТЗ);
ТЗСортированная = Запрос.Выполнить().Выгрузить();
ДокументОбъект.Запасы.Загрузить(ТЗСортированная);
Важно помнить, что объект ТаблицаЗначений является исключительно серверным типом данных. В тонком клиенте и веб-клиенте работа с ним напрямую невозможна. Все операции по выгрузке, обработке и обратной загрузке необходимо выполнять на стороне сервера (в процедурах с директивой &НаСервере или &НаСервереБезКонтекста).
Если вы работаете в модуле управляемой формы, где табличная часть представлена коллекцией ДанныеФормыКоллекция, для работы через таблицу значений используйте методы контекстного преобразования формы РеквизитФормыВЗначение() и ЗначениеВРеквизитФормы().