Как получить и отобразить иерархию данных из внешней базы в СКД

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

При интеграции различных систем 1С часто возникает задача передачи иерархических данных (например, справочников Номенклатура или Контрагенты) через HTTP-сервисы. Стандартная проблема заключается в том, что при получении данных в виде «плоской» таблицы значений программисты начинают вручную прописывать уровни вложенности через Родитель.Наименование, Родитель.Родитель.Наименование и так далее. Это приводит к созданию жесткой структуры с фиксированным количеством уровней и появлению неприятных «пустых группировок» в отчетах, если реальная вложенность элементов различается.

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

Метод 1. Настройка собственной иерархии в СКД

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

Проанализируем алгоритм действий:

  1. Подготовка данных на стороне источника: При выполнении HTTP-запроса к удаленной базе необходимо получить как минимум два ключевых поля для каждой записи: уникальный идентификатор самого элемента (например, Ссылка или UID) и уникальный идентификатор его родителя (РодительUID).
  2. Загрузка в Набор данных - объект: Полученные данные помещаются в ТаблицаЗначений, которая затем передается в СКД. Важно, чтобы типы данных в колонках Ссылка и Родитель совпадали.
  3. Настройка связей наборов данных: Это ключевой этап. Перейдем в схему компоновки данных на закладку «Связи наборов данных».

Разберем по шагам, как настроить связь для построения иерархии:

После этой настройки в настройках отчета (закладка «Настройки» -> «Группировки») вместо обычной группировки по полю Ссылка можно будет выбрать тип группировки «Иерархия». СКД сама рекурсивно обойдет таблицу и построит дерево. Главное преимущество здесь в том, что если у элемента нет родителя, система не будет создавать пустых уровней, что полностью решает проблему «лишних» группировок.

Метод 2. Использование транзитивного замыкания (Closure Table)

Рассмотрим ситуацию, когда база-источник содержит десятки тысяч элементов с глубокой вложенностью. Передавать полную таблицу и заставлять СКД строить связи на лету может быть накладно для производительности. В таких случаях эффективно использовать математический подход под названием «Транзитивное замыкание».

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

Пример структуры такой таблицы:

Проанализируем преимущества этого подхода:

Во-первых, вы можете одним простым запросом ГДЕ Предок = &НужнаяГруппа получить все дочерние элементы любого уровня вложенности. Во-вторых, это позволяет строить отчеты в «плоском» виде, но с сохранением всей информации об иерархии для фильтрации. Для реализации этого метода на стороне источника (удаленной базы) можно использовать временные таблицы в запросе с соединением справочника самим с собой несколько раз или воспользоваться готовыми решениями по генерации текста запроса для транзитивного замыкания.

Метод 3. Динамическое формирование текста запроса

Если по каким-то причинам использование «Собственной иерархии» в СКД невозможно, и вам приходится работать с плоской таблицей с колонками Родитель1, Родитель2, мы можем оптимизировать процесс формирования запроса. Рассмотрим, как избежать избыточности.

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


// Определяем максимальный уровень вложенности справочника
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ МАКСИМУМ(Уровень) КАК МаксУровень ИЗ Справочник.Номенклатура";
Результат = Запрос.Выполнить().Выгрузить();
МаксимальнаяГлубина = Результат[0].МаксУровень;

// Динамически формируем текст запроса для HTTP-ответа
ТекстЗапроса = "ВЫБРАТЬ Ссылка КАК Элемент";
Для Итератор = 1 По МаксимальнаяГлубина Цикл
    Точки = "";
    Для к = 1 По Итератор Цикл
        Точки = Точки + ".Родитель";
    КонецЦикла;
    ТекстЗапроса = ТекстЗапроса + ", Ссылка" + Точки + ".Наименование КАК Родитель" + Итератор;
КонецЦикла;
ТекстЗапроса = ТекстЗапроса + " ИЗ Справочник.Номенклатура";

Такой подход позволяет передавать ровно столько данных, сколько реально существует в базе, минимизируя трафик и количество пустых колонок. Однако помните, что это все равно создает «плоскую» структуру, которая менее удобна для пользователя, чем полноценное дерево в СКД.

Метод 4. Передача данных через JSON-дерево

Если вы контролируете разработку HTTP-сервиса на стороне источника, рассмотрим вариант передачи данных сразу в древовидном формате JSON. Это избавит принимающую сторону от необходимости логического восстановления связей.

На стороне источника создается рекурсивная функция, которая обходит справочник и формирует структуру объектов Соответствие или Структура, вложенных друг в друга. Пример логики:


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

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

Как избежать пустых группировок (Литеры)

Проанализируем ситуацию, описанную автором темы: у некоторых элементов есть Родитель1 и Родитель2, а у некоторых — нет. При использовании жесткой структуры колонок в отчете неизбежно появятся пустые строки в группировках. Чтобы этого избежать при работе с СКД, всегда стремитесь к использованию одной колонки «Родитель» в связке с механизмом собственной иерархии (Метод 1).

Важный нюанс: Если данные загружаются во временную таблицу (МВТ) или объектный набор данных, убедитесь, что в поле Родитель для корневых элементов записано значение NULL или пустая ссылка соответствующего типа. Если там будет «битая» ссылка или значение неопределенного типа, СКД не сможет корректно сопоставить корень дерева, и иерархия может не отобразиться.

Резюме

Для решения проблемы получения иерархии из внешней базы наиболее эффективным является сочетание передачи плоской таблицы (ID + ParentID) и настройки Связей наборов данных в СКД. Это позволяет:

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

← На главную