Разработка и Конфигурация · 11 мин
Дерево значений в 1С: способы сохранения и восстановления
Как сохранить дерево значений в 1С: сериализация в XML и JSON, хранилище значения, файл обмена, передача между клиентом и сервером. Примеры кода и типичные ошибки.
Дерево значений в 1С — объект, который существует только в оперативной памяти сеанса. Как только сеанс завершён или форма закрыта, данные теряются, если разработчик не предусмотрел механизм сохранения. В отличие от справочников и документов, дерево значений не имеет встроенной записи в базу данных — это чисто программная коллекция для промежуточной обработки и отображения иерархии.
На практике задача «сохранить дерево значений» возникает в нескольких сценариях: нужно запомнить настройки пользователя, передать иерархию между клиентом и сервером, выгрузить структуру в файл для обмена с другой системой или сохранить результат обработки, чтобы не строить дерево заново. Для каждого сценария есть свой рабочий инструмент, и выбор неправильного — частая причина потери данных или ошибок сериализации.
Ниже разобраны основные способы: через объект ЗначениеВСтрокуВнутр, сериализацию в XML и JSON, хранилище значения в реквизите объекта, сохранение в файл на диск и передачу между клиентом и сервером в управляемых формах.
Почему дерево значений нельзя сохранить напрямую
Дерево значений (ДеревоЗначений) — несериализуемый сам по себе объект встроенного языка. Если попытаться присвоить его реквизиту справочника или документа, система выдаст ошибку несоответствия типов: в базе данных могут храниться только примитивные типы, ссылки и специальные контейнеры вроде ХранилищеЗначения.
Вторая особенность — дерево привязано к сеансу. Даже если объект объявлен в модуле, после перезапуска сеанса или переоткрытия формы его содержимое обнуляется. Поэтому любое «сохранение» дерева значений — это фактически преобразование его в строку, файл или двоичные данные с последующим восстановлением.
Третий нюанс касается управляемых форм: дерево, объявленное как локальная переменная модуля формы, не переживает серверные вызовы. Чтобы оно жило между вызовами, его нужно оформить как реквизит формы — тогда платформа сама заботится о передаче данных между клиентом и сервером в пределах сеанса формы.
Сохранение через ЗначениеВСтрокуВнутр
Самый компактный способ — функция ЗначениеВСтрокуВнутр(). Она преобразует почти любой сериализуемый объект, включая дерево значений, во внутреннее строковое представление платформы. Обратное преобразование выполняется функцией ЗначениеИзСтрокиВнутр().
// Сохранение
СтрокаДерева = ЗначениеВСтрокуВнутр(ДеревоНоменклатуры);
// Восстановление
ДеревоНоменклатуры = ЗначениеИзСтрокиВнутр(СтрокаДерева);
Способ удобен для служебного хранения: результат можно положить в строковый реквизит неограниченной длины, в константу или в параметр сеанса через хранилище настроек. Недостаток — формат закрытый: прочитать такую строку может только сама платформа 1С, и совместимость между сильно различающимися версиями платформы не гарантируется.
Важное ограничение: если в дереве есть колонки типа ХранилищеЗначения или ссылочные значения, они сериализуются, но при восстановлении в другой информационной базе ссылки станут «битыми» — уникальные идентификаторы не совпадут. Для межбазового обмена этот способ не подходит.
Хранение в базе через ХранилищеЗначения
Когда дерево нужно привязать к конкретному объекту конфигурации — например, сохранить иерархию настроек для элемента справочника, — стандартное решение: добавить объекту реквизит типа ХранилищеЗначения и помещать в него дерево через конструктор Новый ХранилищеЗначения().
// Запись
ОбъектНастроек = Справочники.НастройкиПользователя.СоздатьЭлемент();
ОбъектНастроек.ДанныеДерева = Новый ХранилищеЗначения(ДеревоНоменклатуры, Новый СжатиеДанных(9));
ОбъектНастроек.Записать();
// Чтение
Дерево = ОбъектНастроек.ДанныеДерева.Получить();
Метод Получить() возвращает исходный объект, если он был сериализуемым — дерево значений восстанавливается полностью, со всеми уровнями иерархии и типами колонок. Второй параметр конструктора включает сжатие, что полезно для больших деревьев, чтобы не раздувать таблицу базы.
- 1Добавьте объекту конфигурации реквизит типа ХранилищеЗначения
- 2Поместите дерево: Новый ХранилищеЗначения(Дерево)
- 3Вызовите Записать() у объекта
- 4При чтении вызовите Реквизит.Получить() и проверьте тип результата
- 5Проверьте восстановленное дерево: количество строк и наличие колонок
Типичная ошибка — забыть вызвать Получить() и работать с самим хранилищем как с деревом. Признак проблемы: попытка обратиться к Строки у объекта хранилища вызывает ошибку «Поле объекта не обнаружено».
Выгрузка дерева в XML и JSON
Для обмена с внешними системами дерево сериализуют в открытые форматы. Встроенный СериализаторXDTO умеет записывать дерево значений в XML штатно:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ДеревоНоменклатуры);
СтрокаXML = ЗаписьXML.Закрыть();
Обратное чтение выполняется через СериализаторXDTO.ПрочитатьXML(). Способ подходит для передачи между базами 1С, но сторонняя система такой XML поймёт с трудом из-за служебных типов платформы.
Для интеграции с веб-сервисами и внешними приложениями дерево обычно преобразуют вручную: обходят строки рекурсивно и формируют массив структур, который затем записывают в JSON через ЗаписьJSON. Это даёт полный контроль над именами полей и структурой вложенности.
Функция ДеревоВМассив(Строки)
Результат = Новый Массив;
Для Каждого Строка Из Строки Цикл
Элемент = Новый Структура("Наименование,Код", Строка.Наименование, Строка.Код);
Элемент.Вставить("Подчиненные", ДеревоВМассив(Строка.Строки));
Результат.Добавить(Элемент);
КонецЦикла;
Возврат Результат;
КонецФункции
Сохранение в файл на диске
Если дерево нужно передать пользователю или сохранить как внешнюю копию, данные записывают в файл. Два рабочих варианта: XML через сериализатор (сохраняет типы и иерархию точно) либо табличные форматы (CSV, MXL, Excel) — но они плоско представляют иерархию, и для восстановления дерева придётся кодировать уровни вручную, например отступами или служебной колонкой «Уровень».
На клиенте в управляемом приложении прямая запись файла требует либо диалога выбора файла (ДиалогВыбораФайла), либо передачи двоичных данных с сервера через временное хранилище: сервер формирует файл, помещает его в ПоместитьВоВременноеХранилище(), клиент забирает по адресу и сохраняет через ПолучитьФайл() или НачатьПолучениеФайлов().
Для резервного копирования настроек практичнее всего комбинация: ЗначениеВСтрокуВнутр() → запись строки в текстовый файл. Восстановление — обратное чтение файла и ЗначениеИзСтрокиВнутр() с обязательной проверкой результата в попытке-исключении, так как повреждённый файл вызовет ошибку разбора.
Дерево значений в управляемой форме
Чтобы дерево «жило» на форме между серверными вызовами, добавьте реквизит формы типа ДеревоЗначений и вложенные реквизиты-колонки. Платформа сама сериализует такой реквизит при передаче между клиентом и сервером — дополнительных действий не требуется.
Если дерево строится программно и колонки заранее неизвестны, их добавляют методом ИзменитьРеквизиты() формы. После этого колонки становятся доступны для привязки к элементам формы и сохраняются в течение жизни формы.
Для сохранения состояния дерева между сеансами (развёрнутые ветки, позиция курсора) используют хранилище настроек: ХранилищеОбщихНастроек.Сохранить() и ХранилищеОбщихНастроек.Загрузить(). Само дерево туда лучше класть через ЗначениеВСтрокуВнутр(), так как настройки сериализуются платформой и не всякий объект переживёт эту процедуру корректно.
Сравнение способов сохранения
Быстро и компактно, но только внутри одной базы и закрытый формат
Привязка к объекту базы, сжатие; не подходит для обмена с внешними системами
Обмен между базами 1С с сохранением типов; громоздкий формат для сторонних систем
Интеграция с веб-сервисами; требует ручного обхода дерева
Хранение только в пределах открытой формы, без записи в базу
Проверка результата и ограничения
После восстановления дерева всегда проверяйте три вещи: результат не равен Неопределено, тип результата — именно ДеревоЗначений (ТипЗнч()), количество колонок и строк соответствует ожиданиям. Пустой реквизит хранилища возвращает Неопределено, и обращение к Строки у него вызовет ошибку.
Ограничения, о которых стоит помнить: очень большие деревья (десятки тысяч строк с десятками колонок) при сериализации дают ощутимый объём данных — сжатие обязательно. Ссылочные значения в колонках привязывают дерево к конкретной базе. Наконец, версия платформы имеет значение: строка, созданная ЗначениеВСтрокуВнутр() на новой платформе, может не прочитаться на старой.
Как проверить восстановление дерева
Тип ДеревоЗначений, строки и колонки на месте
Неопределено или ошибка разбора строки
Ссылки открываются, запросы по ним работают
Пустые представления, ошибки «Объект не найден»
Уровни вложенности совпадают с исходными
Все строки на одном уровне — потеряна структура
Частые вопросы
Можно ли сохранить дерево значений в константу?
Да, если константа имеет тип ХранилищеЗначения — дерево помещается через Новый ХранилищеЗначения(Дерево). Альтернатива — строковая константа неограниченной длины с результатом ЗначениеВСтрокуВнутр(). Для часто меняющихся данных константа не лучший выбор: её изменение требует монопольного доступа при определённых условиях и фиксируется в транзакции.
Почему после восстановления из строки дерево пустое?
Чаще всего строка была повреждена при передаче (обрезана, изменена кодировка) или сохранялся не тот объект. Проверьте длину строки до и после, а также оберните ЗначениеИзСтрокиВнутр() в Попытка/Исключение и проверьте тип результата через ТипЗнч().
Как передать дерево значений с сервера на клиент в управляемой форме?
Напрямую объект ДеревоЗначений между клиентом и сервером не передаётся. Используйте реквизит формы типа ДеревоЗначений — платформа передаёт его автоматически. Либо сериализуйте дерево в строку на сервере и восстановите на клиенте, если клиент толстый.
Сохраняются ли типы колонок при сериализации?
При использовании ЗначениеВСтрокуВнутр, ХранилищеЗначения и СериализатораXDTO типы колонок сохраняются полностью. При ручной выгрузке в JSON или CSV типы теряются — их нужно восстанавливать программно при загрузке, например пересоздавая колонки с нужным ОписаниеТипов.
Что делать, если дерево содержит картинки или двоичные данные?
Двоичные данные и картинки сериализуются штатными механизмами (ЗначениеВСтрокуВнутр, ХранилищеЗначения), но сильно увеличивают объём. Для больших файлов лучше хранить их отдельно, а в дереве держать только ссылки или идентификаторы.
Можно ли сохранить дерево значений в регистр сведений?
Да, через ресурс типа ХранилищеЗначения — механика та же, что и со справочником. Это удобно для хранения нескольких вариантов дерева по измерениям, например отдельное дерево настроек для каждого пользователя и каждого отчёта.
Что важно запомнить
Дерево значений — объект сеанса, в базу напрямую не пишется. Для хранения используйте ХранилищеЗначения или ЗначениеВСтрокуВнутр, для обмена — XML/JSON, для формы — реквизит типа ДеревоЗначений. После восстановления всегда проверяйте тип и структуру результата.