Как правильно выгрузить результат запроса в иерархическое дерево значений через COM-соединение?

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

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

Анализ проблемы: почему дерево становится «плоским»

Проанализируем базовый запрос, который часто используется для получения групп номенклатуры. Проблема заключается не только в тексте запроса, но и в способе обработки его результата. Когда мы используем конструкцию ИТОГИ ПО Ссылка ТОЛЬКО ИЕРАРХИЯ, платформа ожидает, что дерево будет строиться на основе родительских связей, существующих в базе данных. Но при передаче данных через COM-соединение механизмы сериализации объектов могут работать не так, как внутри одной сессии.

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

Решение 1: Правильное использование итогов и упорядочивания

Разберем по шагам, как составить запрос, чтобы дерево выгружалось корректно. Опыт показывает, что для стабильного формирования иерархии при выгрузке в ДеревоЗначений критически важно наличие предложения УПОРЯДОЧИТЬ ПО вместе с ИТОГИ.

Рассмотрим пример правильного запроса:


Запрос = СоединениеCom.NewObject("Запрос");
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.Ссылка КАК Ссылка,
    |   Номенклатура.Наименование КАК Наименование,
    |   Номенклатура.Код КАК Код
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   Номенклатура.Ссылка В ИЕРАРХИИ(&Ссылка)
    |   И Номенклатура.ЭтоГруппа = ИСТИНА
    |УПОРЯДОЧИТЬ ПО
    |   Наименование
    |ИТОГИ ПО
    |   Ссылка ТОЛЬКО ИЕРАРХИЯ";

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

Важный момент: использование УПОРЯДОЧИТЬ ПО Наименование помогает платформе правильно выстроить последовательность строк перед формированием итогов. При работе через COM это иногда является решающим фактором для корректной интерпретации уровней вложенности методом Выгрузить().

Решение 2: Специфика работы с COM-объектами и перечислениями

Проанализируем ситуацию с методом обхода. При выгрузке результата запроса в дерево через COM-соединение, необходимо использовать системные перечисления именно из того соединения, в котором выполняется запрос. Посмотрим на разницу:

Неправильно:
Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Здесь используется локальное перечисление текущей базы, которое может иметь другой числовой индекс.

Правильно:
Дерево = РезультатЗапроса.Выгрузить(СоединениеCom.ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

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

Проблема пустого корня (первого уровня)

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

Также проверьте, не попадает ли в параметр &Ссылка корень справочника. Если вы запрашиваете иерархию от корня, система может добавить пустую ссылку как вершину иерархии.

Решение 3: Использование предложения «ИЕРАРХИЯ» в упорядочивании

Существует альтернативный способ получения иерархического списка, который часто путают с итогами. Рассмотрим предложение УПОРЯДОЧИТЬ ПО Ссылка ИЕРАРХИЯ. Посмотрим на пример:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.ЭтоГруппа = ИСТИНА
УПОРЯДОЧИТЬ ПО
    Ссылка ИЕРАРХИЯ

Важное отличие: этот метод не создает физическое дерево в объекте ДеревоЗначений. Он возвращает плоский список, но строки в нем расположены в «деревовидном» порядке: сначала идет группа, затем сразу за ней все её потомки. Если вам нужно просто отобразить данные в списке, имитирующем дерево, этот способ работает быстрее и стабильнее через COM, так как передается обычная ТаблицаЗначений.

Альтернативный метод: ручное построение дерева

Если стандартные средства выгрузки через COM продолжают выдавать некорректный результат (что иногда случается на старых релизах платформы или при сильно разреженных данных), рекомендуется применить алгоритм ручного восстановления иерархии:

  1. Выгрузите результат запроса во внешнюю ТаблицаЗначений без итогов (плоскую таблицу), обязательно добавив поле Родитель.
  2. Передайте эту таблицу в свою базу.
  3. Создайте пустое ДеревоЗначений локально.
  4. Используя рекурсивную функцию, заполните дерево, находя в таблице строки с соответствующим Родителем.

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

Подведем итог: для получения качественного дерева через COM всегда используйте упорядочивание, обращайтесь к перечислениям через объект соединения и следите за тем, чтобы фильтры ГДЕ не «разрывали» цепочку родительских связей в результатах запроса.

← На главную