Как программно вывести иерархию справочника в дерево значений, начиная с выбранного элемента?

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

Часто перед разработчиками 1С встает задача: необходимо отобразить часть иерархического справочника в виде ДеревоЗначений на форме, где корнем дерева является не весь справочник, а конкретный, выбранный пользователем элемент. Попытки использовать стандартный запрос с ИТОГИ ПО часто приводят к появлению дублей или необходимости сложной обработки «мусорных» данных. Давайте разберем наиболее элегантный и производительный способ решения этой задачи.

Почему запросы с итогами не всегда подходят?

Использование конструкции ИТОГИ ПО Ссылка ИЕРАРХИЯ отлично подходит для отчетов, но в случае с программной структурой ДеревоЗначений мы сталкиваемся с тем, что 1С включает в результат и самого родителя, и все детальные записи. Это создает «лишние» уровни и повторы, которые приходится удалять сложными циклами. Нам же нужно чистое дерево, начинающееся с выбранного узла. Рассмотрим, как построить такое дерево, исключив обращение к базе данных внутри циклов.

Алгоритм построения дерева через кэширование

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

Шаг 1. Получение данных.

Сначала мы получаем все подчиненные элементы одним запросом. Это критически важно для производительности, так как мы полностью избегаем «запросов в цикле».


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Спр.Ссылка,
    |   Спр.Родитель
    |ИЗ
    |   Справочник.ВашСправочник КАК Спр
    |ГДЕ
    |   Спр.Ссылка В ИЕРАРХИИ(&Корень)";
Запрос.УстановитьПараметр("Корень", ВыбранныйЭлемент);
ТЗ = Запрос.Выполнить().Выгрузить();

Шаг 2. Построение структуры дерева.

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


Дерево = Новый ДеревоЗначений;
Дерево.Колонки.Добавить("Ссылка");

КореньДерева = Дерево.Строки.Добавить();
КореньДерева.Ссылка = ВыбранныйЭлемент;

Кэш = Новый Соответствие;
Кэш.Вставить(ВыбранныйЭлемент, КореньДерева);

Шаг 3. Заполнение дерева через рекурсивный обход или циклическую обработку.

Теперь, имея плоскую таблицу ТЗ, мы проходим по ней и расставляем элементы по местам. Важно учитывать, что при добавлении новой строки в ДеревоЗначений, мы должны сразу поместить её в Кэш, чтобы следующие элементы могли найти своего родителя.


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

Преимущества данного решения

  1. Производительность: Мы выполняем ровно один запрос к базе данных. Все манипуляции с деревом происходят в оперативной памяти.
  2. Лаконичность: Отсутствует необходимость в написании сложных обработчиков и «чистке» результата запроса от итоговых записей.
  3. Гибкость: Этот код легко адаптируется под любой справочник, достаточно лишь изменить имя объекта в запросе.
  4. Отсутствие дублей: Мы сами контролируем процесс добавления строк, поэтому дублирование элементов исключено на уровне логики алгоритма.

Важные замечания

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

Этот подход является «золотым стандартом» при ручном формировании иерархических структур в 1С, когда стандартные возможности запросов или СКД оказываются недостаточно гибкими для ваших визуальных задач.

← На главную