Довольно часто в практике программиста 1С встречается интересная задача: имеется справочник с глубокой иерархией (например, Номенклатура со структурой "Продукция — Категория — Вид" и уровнем вложенности вплоть до 10). Требуется выстроить все группы в одну таблицу так, чтобы каждый уровень иерархии располагался в отдельной колонке (Продукция | Категория | Вид). Дополнительно может потребоваться получить иерархию только до определенного уровня (например, остановиться только на категориях).
Разберем по шагам, как можно подойти к решению данной задачи, проанализируем частые ошибки при написании кода и рассмотрим наиболее оптимальные современные методы.
Посмотрим на пример кода, который часто пытаются использовать для решения первой части задачи — раскидывания уровней по колонкам с помощью рекурсивного обхода.
Процедура ОбойтиУровеньДереваБезСС(Строки)
Для каждого Строка из Строки Цикл
НомерКолонки = Строка.Уровень(); //Номер колонок групп
ИмяКолонкиНом = "ПродукцияНом";//Имя колонки продукции
СтрокаТаблицыИтогов = ТаблицаПоГруппировкам.Добавить();
Если Строка.Строки.Количество() > 0 тогда
ИмяКолонки = "группа" + НомерКолонки;
КвалификаторыЧисла = Новый КвалификаторыСтроки(100);
Массив = Новый Массив;
Массив.Добавить(Тип("Строка"));
ЧисловойТип = Новый ОписаниеТипов(Массив, , ,КвалификаторыЧисла);
Если ТаблицаПоГруппировкам.Колонки.Найти("группа"+ИмяКолонки) <> Неопределено Тогда
ЭлементыФормы.ТаблицаПоГруппировкам.СоздатьКолонки();
СтрокаТаблицыИтогов["группа"+ИмяКолонки] = Строка.Ссылка.Наименование;
Иначе
ТаблицаПоГруппировкам.Колонки.Добавить("группа"+ИмяКолонки,ЧисловойТип,ИмяКолонки);
ЭлементыФормы.ТаблицаПоГруппировкам.СоздатьКолонки();
СтрокаТаблицыИтогов["группа"+ИмяКолонки] = Строка.Ссылка.Наименование;
КонецЕсли;
Иначе
// Аналогичный код для элементов
// ...
КонецЕсли;
ОбойтиУровеньДереваБезСС(Строка.Строки);
КонецЦикла;
КонецПроцедуры
Проанализируем этот подход. Автор пытается на лету, прямо во время обхода дерева, добавлять новые колонки в таблицу значений и сразу же перерисовывать элементы формы.
Критическая ошибка текущего кода: использование метода ЭлементыФормы.ТаблицаПоГруппировкам.СоздатьКолонки() внутри цикла. Это крайне ресурсоемкая операция. Перестроение элементов управления на форме при каждой итерации рекурсии приведет к катастрофическому падению производительности, особенно если в справочнике тысячи элементов.
Как сделать правильно:
СоздатьКолонки().Самым правильным, современным и быстрым инструментом для вывода иерархии в отдельные колонки в 1С является СКД.
Поскольку максимальный уровень вложенности нам примерно известен (например, не больше 10), мы можем решить задачу еще на этапе написания запроса СКД. Рассмотрим подробнее этот механизм:
Номенклатура.Родитель КАК Уровень2, Номенклатура.Родитель.Родитель КАК Уровень1. Это жестко зафиксирует колонки, если структура справочника строго регламентирована.Выбор Когда Уровень() = 0 Тогда Неопределено Иначе Номенклатура Конец. Это позволит скрыть ненужные промежуточные группировки.Выясним способы ограничения выборки конкретным уровнем (например, вывести справочник, остановившись только на уровне "Вид").
Способ 1: Через СКД
В системе компоновки данных существуют встроенные системные поля Уровень() и УровеньВГруппировке. Используя их, мы можем легко наложить отбор прямо в пользовательских настройках отчета (например, установить отбор Уровень() = 2).
Способ 2: Через язык запросов
В языке запросов 1С нет встроенной функции получения уровня вложенности элемента напрямую. Однако получить иерархическую структуру можно с помощью конструкции ИТОГИ ПО ... ТОЛЬКО ИЕРАРХИЯ.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Элемент
ИЗ
Справочник.Номенклатура КАК Номенклатура
ИТОГИ ПО
Элемент ТОЛЬКО ИЕРАРХИЯ
Если требуется получить дерево с четким пониманием уровня прямо из запроса в виде плоской таблицы, разработчики часто применяют соединения справочника с самим собой по полю Родитель. Для каждого уровня вложенности добавляется свое левое соединение, и вычисляется поле Уровень = 1 + ....
Способ 3: Ограничение на форме (Визуальное)
Если задача заключается просто в том, чтобы визуально ограничить список элементов на форме (в обычных или управляемых формах), то следует использовать свойство РодительВерхнегоУровня. Если программно задать в это свойство конкретную группу, табличное поле будет отображать список начиная исключительно с этого родителя, игнорируя всё, что находится выше по иерархии.
Итог: Программный обход справочников и деревьев с ручным формированием колонок оправдан только в очень нестандартных задачах. В 90% случаев для вывода иерархии в отдельные колонки и отбора по уровню следует использовать возможности Системы Компоновки Данных (СКД) — это сэкономит ресурсы системы и время разработчика.