Как сохранить ДеревоЗначений на форме документа?

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

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

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

Метод 1: Сохранение структуры в плоскую Табличную Часть

Наиболее надежный и «прозрачный» с точки зрения платформы способ — это использование стандартной табличной части документа для хранения строк дерева. Поскольку табличная часть (ТЧ) всегда плоская, нам необходимо научить систему восстанавливать иерархию при открытии формы. Разберем этот алгоритм по шагам.

Для реализации нам потребуется добавить в табличную часть документа два служебных реквизита:

  1. КлючСтроки (тип Число или УникальныйИдентификатор) — идентификатор текущей строки.
  2. КлючРодителя (тип тот же) — ссылка на идентификатор родительской строки. Если строка находится в корне дерева, это поле остается пустым или равным 0.

Рассмотрим, как реализовать выгрузку данных из дерева в таблицу перед записью документа. Для этого проанализируем рекурсивный метод обхода:


Процедура ВыгрузитьДеревоВТабличнуюЧасть(СтрокиДерева, ТЧДокумента, РодительID = 0)
    Для Каждого СтрокаДерева Из СтрокиДерева Цикл
        НоваяСтрокаТЧ = ТЧДокумента.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрокаТЧ, СтрокаДерева);
        
        // Генерация уникального ключа для текущей строки
        ТекущийID = ТЧДокумента.Количество(); 
        НоваяСтрокаТЧ.КлючСтроки = ТекущийID;
        НоваяСтрокаТЧ.КлючРодителя = РодительID;
        
        // Рекурсивный вызов для подчиненных строк
        ВыгрузитьДеревоВТабличнуюЧасть(СтрокаДерева.Строки, ТЧДокумента, ТекущийID);
    КонецЦикла;
КонецПроцедуры

При открытии документа нам нужно выполнить обратную операцию. Мы прочитаем плоскую таблицу и восстановим дерево. Выясним, как это сделать эффективно:


Процедура ВосстановитьДеревоИзТабличнойЧасти(ТЧДокумента, ДеревоОбъект)
    // Сначала создаем соответствие для быстрого поиска родительских узлов в дереве
    СоответствиеУзлов = Новый Соответствие;
    
    Для Каждого СтрокаТЧ Из ТЧДокумента Цикл
        Если СтрокаТЧ.КлючРодителя = 0 Тогда
            НоваяСтрокаДерева = ДеревоОбъект.Строки.Добавить();
        Иначе
            РодительскийУзел = СоответствиеУзлов.Получить(СтрокаТЧ.КлючРодителя);
            НоваяСтрокаДерева = РодительскийУзел.Строки.Добавить();
        КонецЕсли;
        
        ЗаполнитьЗначенияСвойств(НоваяСтрокаДерева, СтрокаТЧ);
        СоответствиеУзлов.Вставить(СтрокаТЧ.КлючСтроки, НоваяСтрокаДерева);
    КонецЦикла;
КонецПроцедуры

Метод 2: Особенности работы на Управляемых Формах

Если мы работаем с современным интерфейсом (Управляемые формы), важно помнить о разделении контекста между клиентом и сервером. На клиенте объект ДеревоЗначений недоступен — там используется тип ДанныеФормыДерево. Проанализируем, как правильно передать данные для сохранения.

Для преобразования визуального элемента формы в объект, с которым можно работать на сервере, используем метод РеквизитФормыВЗначение. Посмотрим на пример кода в модуле формы:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // Преобразуем данные формы (дерево) в объект ДеревоЗначений
    ДеревоОбъект = РеквизитФормыВЗначение("ДеревоНаФорме");
    
    // Очищаем ТЧ документа и заполняем её данными из дерева
    ТекущийОбъект.СоставДерева.Очистить();
    ВыгрузитьДеревоВТабличнуюЧасть(ДеревоОбъект.Строки, ТекущийОбъект.СоставДерева);
КонецПроцедуры

Соответственно, в процедуре ПриЧтенииНаСервере или ПриСозданииНаСервере мы должны выполнить обратную операцию, используя ЗначениеВРеквизитФормы, чтобы дерево снова появилось на экране пользователя.

Метод 3: Использование Хранилища Значения

Рассмотрим альтернативный вариант: создание реквизита документа с типом ХранилищеЗначения. Этот метод кажется проще, так как 1С позволяет сериализовать (свернуть в двоичные данные) практически любой объект, включая ДеревоЗначений.

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

Недостатки и риски:

Если вы выбрали этот путь, используйте следующий подход для записи:


ОбъектДокумент.ДанныеДереваХранилище = Новый ХранилищеЗначения(ДеревоЗначенийОбъект);

И для восстановления:


ДеревоИзХранилища = ОбъектДокумент.ДанныеДереваХранилище.Получить();
Если ТипЗнч(ДеревоИзХранилища) = Тип("ДеревоЗначений") Тогда
    ЗначениеВРеквизитФормы(ДеревоИзХранилища, "ДеревоНаФорме");
КонецЕсли;

Метод 4: Хранение параметров построения вместо самих данных

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

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

Рекомендации и итоги

Выясним, какой метод выбрать в конкретной ситуации:

Таким образом, мы разобрали основные механики работы с иерархическими структурами в документах. Выбор конкретного способа зависит от требований к производительности и необходимости анализа этих данных в будущем через отчетную систему.

← На главную