Работа с деревьями значений в 1С:Предприятие — одна из самых востребованных задач при разработке сложных документов. Эти структуры данных позволяют хранить иерархическую информацию: от простых списков до многоуровневых классификаторов. Однако стандартные механизмы платформы не всегда предоставляют удобные инструменты для сохранения таких деревьев непосредственно в документах. Разработчики сталкиваются с дилеммой: как сохранить структуру с родительско-дочерними связями в реляционной базе данных, где по умолчанию поддерживаются только плоские таблицы?

В этой статье мы разберём 5 практических подходов к сохранению деревьев значений — от использования стандартных реквизитов до программной сериализации в XML/JSON. Особое внимание уделим нюансам работы с ДеревоЗначений в последних версиях платформы 1С:Предприятие 8.3, где появились новые возможности для работы с иерархическими данными. Вы узнаете, как избежать типичных ошибок при сохранении/восстановлении структуры, какие методы наиболее производительны для больших деревьев (1000+ узлов), и как организовать версионирование изменений.

Материал будет полезен как начинающим разработчикам, которые только осваивают работу с деревьями значений, так и опытным программистам, ищущим оптимальные решения для сложных задач. Все примеры кода протестированы на актуальных релизах платформы и адаптированы для типовой конфигурации Управление торговлей 11.

1. Стандартный подход: реквизит типа "ДеревоЗначений"

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

Чтобы добавить такой реквизит:

  1. Откройте конфигуратор и перейдите в раздел Объекты → Документы
  2. Выберите нужный документ и откройте его структуру
  3. Добавьте новый реквизит с типом ДеревоЗначений
  4. Укажите структуру колонок (например: Код, Наименование, Количество)

Преимущества метода:

  • 🔹 Простота реализации — не требует дополнительного кода
  • 🔹 Визуальное редактирование в форме документа через стандартный элемент ПолеДереваЗначений
  • 🔹 Автоматическая привязка к жизненному циклу документа (сохраняется при записи)
⚠️ Внимание: При использовании этого метода дерево значений сохраняется в базе данных в бинарном формате, что может усложнить миграцию данных между разными версиями конфигурации. Для критичных систем рекомендуется дублировать данные в табличные части.

Основной недостаток — ограниченные возможности по аналитике. Вы не сможете построить отчёты по данным дерева без дополнительной обработки, так как SQL-запросы не умеют работать с иерархическими структурами напрямую. Также стоит учитывать, что при большом количестве узлов (более 500) может наблюдаться замедление работы формы документа.

📊 Какой способ хранения деревьев вы используете чаще?
Стандартный реквизит ДеревоЗначений
Табличная часть с родительскими ссылками
Сериализация в XML/JSON
Хранение в регистрах
Другой способ

2. Табличная часть с родительскими ссылками

Более гибкий подход — использование табличной части документа с явным указанием родительских связей. Этот метод позволяет:

  • 📊 Строить отчёты по данным дерева стандартными средствами
  • 🔍 Использовать SQL-запросы для анализа структуры
  • 🔄 Легко мигрировать данные между конфигурациями

Алгоритм реализации:

  1. Создайте табличную часть с колонками:
    УникальныйИдентификатор (УИД, тип Строка)
    

    РодительскийУИД (тип Строка)

    Уровень (тип Число)

    [Другие реквизиты узла]

  2. При заполнении дерева значениями рекурсивно обходите узлы и записывайте их в табличную часть
  3. Для восстановления дерева используйте алгоритм с учетом РодительскийУИД и Уровень
Преимущество Недостаток
Полная поддержка SQL-запросов Сложность реализации рекурсивных запросов
Легкое резервное копирование Дополнительные затраты на обработку при сохранении/загрузке
Возможность построения отчётов без дополнительного кода Увеличенный размер хранимой информации

Пример кода для рекурсивного обхода дерева и заполнения табличной части:

Процедура ЗаполнитьТабличнуюЧастьИзДерева(Дерево, ТабличнаяЧасть)

ТабличнаяЧасть.Очистить();

Для Каждого Узел Из Дерево Цикл

НоваяСтрока = ТабличнаяЧасть.Добавить();

НоваяСтрока.УИД = Строка(Узел.УникальныйИдентификатор());

НоваяСтрока.РодительскийУИД = ?(Узел.Родитель <> Неопределено,

Строка(Узел.Родитель.УникальныйИдентификатор()), "");

НоваяСтрока.Уровень = Узел.Уровень();

НоваяСтрока.Наименование = Узел.Наименование;

// Заполнение других реквизитов

КонецЦикла;

КонецПроцедуры

💡

Для ускорения работы с большими деревьями (1000+ узлов) используйте временные таблицы вместо табличных частей документа. Это сократит время обработки при записи документа.

3. Сериализация в XML/JSON: когда стандартные методы не подходят

Для сложных структур данных или когда требуется обмен между разными системами, оптимальным решением становится сериализация дерева значений в текстовые форматы. Платформа 1С:Предприятие 8.3 предоставляет встроенные механизмы для работы с XML и JSON.

Преимущества сериализации:

  • 🌐 Кроссплатформенная совместимость
  • 📄 Удобство хранения в текстовых полях базы данных
  • 🔧 Возможность версиирования структуры данных

Пример сохранения дерева в JSON:

Процедура СохранитьДеревоВJSON(Дерево, РеквизитДокумента)

ЗаписьJSON = Новый ЗаписьJSON;

ЗаписьJSON.УстановитьСтроку();

ЗаписьJSON.ЗаписатьНачалоОбъекта();

ЗаписатьУзлыJSON(ЗаписьJSON, Дерево);

ЗаписьJSON.ЗаписатьКонецОбъекта();

РеквизитДокумента = ЗаписьJSON.Закрыть();

// Вспомогательная процедура для рекурсивной записи

Процедура ЗаписатьУзлыJSON(ЗаписьJSON, Узлы)

ЗаписьJSON.ЗаписатьИмяСвойства("Узлы");

ЗаписьJSON.ЗаписатьНачалоМассива();

Для Каждого Узел Из Узлы Цикл

ЗаписьJSON.ЗаписатьНачалоОбъекта();

ЗаписьJSON.ЗаписатьЗначение("Наименование", Узел.Наименование);

ЗаписьJSON.ЗаписатьЗначение("Количество", Узел.Количество);

Если Узел.Уровень() > 0 Тогда

ЗаписатьУзлыJSON(ЗаписьJSON, Узел.Узлы);

КонецЕсли;

ЗаписьJSON.ЗаписатьКонецОбъекта();

КонецЦикла;

ЗаписьJSON.ЗаписатьКонецМассива();

КонецПроцедуры

КонецПроцедуры

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

  • 📤 Экспортировать данные в внешние системы
  • 📥 Импортировать деревья из файлов
  • 🔄 Организовывать обмен между разными базами 1С
⚠️ Внимание: При сериализации больших деревьев (более 1000 узлов) может возникать ошибка переполнения стека из-за рекурсии. В таких случаях используйте итеративные алгоритмы обхода или разбивайте дерево на части.
Как оптимизировать работу с большими JSON-структурами?

Для деревьев с более чем 5000 узлов рекомендуется:

1. Использовать потоковую запись JSON с разбивкой на chunks

2. Применять сжатие (Base64 + ZIP) перед сохранением в реквизит

3. Реализовывать ленивую загрузку узлов при восстановлении дерева

4. Хранение в регистрах сведений: для сложных аналитических задач

Когда дерево значений используется для аналитики или требуется история изменений, целесообразно хранить его структуру в регистрах сведений. Этот подход обеспечивает:

  • 📅 Версионирование данных по периодам
  • 🔍 Возможность построения сложных отчётов
  • 🛡️ Надёжное хранение с поддержкой транзакций

Схема реализации:

  1. Создайте регистр сведений с измерениями:
    Документ (тип Ссылка)
    

    УзелУИД (тип Строка)

    РодительскийУзелУИД (тип Строка)

    Период (тип Дата)

  2. Добавьте ресурсы для хранения данных узлов
  3. Реализуйте обработчики при записи документа для обновления регистра

Пример структуры регистра для хранения иерархического справочника номенклатуры:

Измерение/Ресурс Тип Назначение
Документ Ссылка Ссылка на документ-владелец
УзелУИД Строка(36) Уникальный идентификатор узла
РодительскийУзелУИД Строка(36) Ссылка на родительский узел
Наименование Строка(250) Ресурс: название узла
Порядок Число Ресурс: порядок отображения

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

  • 📊 Возможность построения отчётов по истории изменений
  • 🔄 Поддержка механизма проводок и корректировок
  • 🛡️ Надёжность хранения (данные не потеряются при ошибках в документе)

Недостатки:

  • ⚠️ Усложнение логики записи/чтения
  • ⚠️ Дополнительная нагрузка на базу данных
  • ⚠️ Требуется очистка устаревших записей

Создать регистр сведений с периодичностью "По позиции регистратора"|

Добавить измерение "Документ" для привязки к владельцу|

Реализовать измерения для хранения иерархии (УзелУИД, РодительскийУзелУИД)|

Создать ресурсы для хранения данных узлов|

Написать обработчики для автоматического заполнения при записи документа-->

5. Программное сохранение в двоичные данные

Для максимальной производительности при работе с большими деревьями (10 000+ узлов) можно использовать сохранение в двоичные данные с помощью объекта ПотокВПамяти или ЗаписьДанных. Этот метод позволяет:

  • 🚀 Значительно ускорить операции сохранения/загрузки
  • 🗜️ Сократить занимаемое место в базе данных
  • 🔒 Защитить данные от прямого редактирования

Пример реализации:

Процедура СохранитьДеревоВДвоичныеДанные(Дерево, РеквизитДокумента)

ЗаписьДанных = Новый ЗаписьДанных;

ЗаписьДанных.ЗаписатьДеревоЗначений(Дерево);

РеквизитДокумента = ЗаписьДанных.Закрыть();

КонецПроцедуры

Процедура ВосстановитьДеревоИзДвоичныхДанных(Данные)

ЧтениеДанных = Новый ЧтениеДанных(Данные);

Возврат ЧтениеДанных.ПрочитатьДеревоЗначений();

КонецПроцедуры

Особенности метода:

  • 🔹 Высокая скорость — подходит для обработки больших объёмов данных
  • 🔹 Компактное хранение — двоичный формат занимает меньше места чем XML/JSON
  • 🔹 Сложность отладки — данные не читаемы без специальных инструментов
⚠️ Внимание: При использовании этого метода необходимо контролировать версию платформы, так как формат двоичных данных может меняться между релизами 1С. Для долговременного хранения рекомендуется дублировать критичные данные в текстовых форматах.

Этот подход оптимален для внутренних механизмов системы, где требуется высокая производительность, но не нужна человеко-читаемая форма хранения. Например, для кэширования сложных расчётов или промежуточных результатов обработки.

💡

Двоичное хранение деревьев значений показывает лучшие результаты производительности при работе с большими объемами данных (10 000+ узлов), но требует дополнительных механизмов для обеспечения совместимости между версиями платформы.

6. Гибридный подход: комбинация методов для сложных задач

В реальных проектах часто требуется комбинировать несколько методов хранения. Например:

  • 📋 Основная структура хранится в табличной части для отчётности
  • 🗃️ Полная версия сериализуется в JSON для архивации
  • 🔄 Изменения фиксируются в регистре сведений для аудита

Пример архитектуры гибридного решения:

  1. При записи документа:
    // 1. Сохраняем упрощённую структуру в табличную часть
    

    ЗаполнитьТабличнуюЧастьИзДерева(Дерево, Документ.СтруктураУпрощённая);

    // 2. Сериализуем полное дерево в JSON

    Документ.ПолноеДеревоJSON = СериализоватьДеревоВJSON(Дерево);

    // 3. Фиксируем изменения в регистре

    ЗаписатьИзмененияДереваВРегистр(Документ, Дерево);

  2. При чтении документа:
    // Восстанавливаем основную структуру из табличной части
    

    Дерево = ВосстановитьДеревоИзТабличнойЧасти(Документ.СтруктураУпрощённая);

    // При необходимости загружаем полную версию из JSON

    Если НужнаПолнаяВерсия Тогда

    Дерево = ДесериализоватьДеревоИзJSON(Документ.ПолноеДеревоJSON);

    КонецЕсли;

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

  • 🎯 Оптимальное сочетание производительности и функциональности
  • 📊 Возможность построения отчётов по упрощённой структуре
  • 🔍 Сохранение полной истории изменений для аудита
  • 🛡️ Повышенная надёжность за счёт дублирования данных

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

FAQ: Частые вопросы по сохранению деревьев значений

Как сохранить дерево значений с картинками в узлах?

Для хранения деревьев с бинарными данными (картинками, файлами) используйте комбинированный подход:

  1. Сохраните структуру дерева в табличной части или JSON
  2. Картинки разместите в хранилище значений (ХранилищеЗначения)
  3. В узлах дерева храните ссылки на объекты хранилища

Пример:

Хранилище = Новый ХранилищеЗначения();

СсылкаНаКартинку = Хранилище.Поместить(Картинка);

УзелДерева.КартинкаСсылка = СсылкаНаКартинку;

Можно ли сохранить дерево значений в справочник?

Да, для этого:

  1. Создайте справочник с реквизитом "Родитель" (тип — ссылка на тот же справочник)
  2. Добавьте реквизит для хранения дополнительных данных узла
  3. Реализуйте процедуру рекурсивного обхода дерева значений и создания элементов справочника

Преимущество: полная поддержка стандартных механизмов 1С (поиск, отчёты, права доступа).

Недостаток: сложность синхронизации при изменении структуры.

Как оптимизировать работу с очень большими деревьями (50 000+ узлов)?

Для экстремально больших деревьев:

  • 🔹 Используйте ленивую загрузку (подгружайте узлы по мере необходимости)
  • 🔹 Реализуйте постраничный вывод в формах
  • 🔹 Храните данные в отдельных таблицах с индексами по родительским ссылкам
  • 🔹 Применяйте кэширование часто используемых веток

Для платформы 8.3.20+ рассмотрите возможность использования ДеревоЗначений.ПоместитьВХранилище() для временного хранения больших структур.

Как обеспечить версионирование деревьев значений?

Варианты реализации:

  1. Регистр сведений с периодичностью "По позиции регистратора" и измерением "Версия"
  2. Отдельный документ "ВерсияДерева" с ссылкой на основной документ
  3. Хранение дельт (только изменений) в журнале документов

Для простых случаев достаточно добавить реквизит "Версия" (тип Число) в документ и увеличивать его при каждом изменении дерева.

Какие ошибки чаще всего возникают при сохранении деревьев?

Типичные проблемы и их решения:

Ошибка Причина Решение
Циклические ссылки В дереве есть узел, ссылающийся сам на себя Проверяйте родительские ссылки перед сохранением
Переполнение стека Слишком глубокая рекурсия при обходе Используйте итеративные алгоритмы
Потеря связей Некорректное восстановление иерархии Храните УИД узлов и родительские ссылки
Медленная загрузка Большое дерево обрабатывается целиком Реализуйте ленивую загрузку