К статье
Практический материал

Разработка и Конфигурация · 13 мин

Как хранить структуру в реквизите формы 1С

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

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

Основных подхода четыре: сериализация структуры в строку (JSON или через ЗначениеВСтрокуВнутр), хранение в реквизите типа «ХранилищеЗначения», использование реквизита типа «СписокЗначений» или «ТаблицаЗначений», а также программное создание динамических реквизитов формы. У каждого способа есть свои ограничения по типам данных, переносимости между клиентом и сервером и удобству отладки.

Ниже разобраны все варианты с примерами кода, условиями выбора и типичными ошибками, которые приводят к потере данных или ошибкам сериализации.

Почему структуру нельзя просто добавить в реквизит формы

Реквизиты формы в управляемом приложении — это не обычные переменные, а данные, которые платформа сериализует и передаёт между клиентом и сервером при каждом серверном вызове. Поэтому состав допустимых типов ограничен: примитивные типы, ссылки, таблицы и деревья значений, списки значений, хранилище значения и некоторые другие. Структура, соответствие и массив в этот список не входят как самостоятельные типы реквизита.

Это архитектурное ограничение, а не недоработка конкретной версии платформы. Структура — несериализуемый в контексте формы объект: платформа не знает, как безопасно перенести её между тонким клиентом, веб-клиентом и сервером, особенно если внутри лежат вложенные структуры или несериализуемые значения.

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

Способ 1. Сериализация структуры в JSON-строку

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

Для записи используется объект ЗаписьJSON, для чтения — ЧтениеJSON с параметром ПрочитатьВСоответствие, который определяет, вернётся ли результат как структура или как соответствие.

&НаСервере

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

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

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

ЗаписатьJSON(Запись, СтруктураДанных);

ДанныеСтруктурыJSON = Запись.Закрыть();

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

&НаСервере

Функция ПолучитьСтруктуруИзРеквизита()

Чтение = Новый ЧтениеJSON;

Чтение.УстановитьСтроку(ДанныеСтруктурыJSON);

Результат = ПрочитатьJSON(Чтение, Истина);

Чтение.Закрыть();

Возврат Результат;

КонецФункции

Здесь ДанныеСтруктурыJSON — реквизит формы типа «Строка» неограниченной длины. Важно: при чтении с параметром Истина возвращается соответствие, а не структура. Если дальше по коду нужна именно структура (например, для обращения через точку), соответствие нужно перебрать и собрать структуру вручную.

Способ 2. Хранение через ЗначениеВСтрокуВнутр

Функция ЗначениеВСтрокуВнутр упаковывает значение практически любого сериализуемого типа, включая структуру с вложенными структурами, массивами и таблицами значений, во внутреннее строковое представление платформы. Обратное преобразование выполняет ЗначениеИзСтрокиВнутр, которое восстанавливает исходные типы точно.

&НаСервере

Процедура УпаковатьСтруктуру(СтруктураДанных)

СтруктураВнутр = ЗначениеВСтрокуВнутр(СтруктураДанных);

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

&НаСервере

Функция РаспаковатьСтруктуру()

Возврат ЗначениеИзСтрокиВнутр(СтруктураВнутр);

КонецФункции

Главное преимущество перед JSON — полная сохранность типов: дата останется датой, ссылка — ссылкой, вложенная таблица значений — таблицей. Недостатков три: формат внутренний и недокументированный, строка нечитаема при отладке, а главное — совместимость между разными версиями платформы не гарантируется. Поэтому ЗначениеВСтрокуВнутр подходит для временного хранения в рамках сеанса или формы, но не для долговременного хранения в базе данных.

Обе функции доступны только на сервере, поэтому любое обращение к упакованной структуре с клиента потребует серверного вызова. Если логика формы активно работает на клиенте, это может стать узким местом по производительности.

Способ 3. Хранилище значения в реквизите формы

Реквизит формы может иметь тип «ХранилищеЗначения». Структура помещается в хранилище конструктором Новый ХранилищеЗначения(СтруктураДанных), а извлекается методом Получить(). Типы внутри сохраняются полностью, как и при ЗначениеВСтрокуВнутр.

&НаСервере

Процедура ПоместитьВХранилище(СтруктураДанных)

СтруктураХранилище = Новый ХранилищеЗначения(СтруктураДанных);

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

&НаСервере

Функция ИзвлечьИзХранилища()

Возврат СтруктураХранилище.Получить();

КонецФункции

Этот вариант удобен, когда структура большая и обращения к ней редкие: данные упакованы и не захламляют контекст формы. Но хранилище значения нельзя отобразить на форме, его содержимое не видно в отладчике без извлечения, а каждое обращение — это распаковка. Для часто читаемых параметров лучше подходит JSON-строка или таблица значений.

Сравнение способов хранения

JSON-строка

Переносится клиент-сервер, читаема в отладке, но теряет типы ссылок и дат. Подходит для простых параметров.

ЗначениеВСтрокуВнутр

Полностью сохраняет типы, только сервер, формат недокументирован. Для временного хранения в сеансе.

ХранилищеЗначения

Сохраняет типы, компактно в контексте формы, но невидимо в отладке и требует распаковки при каждом доступе.

Таблица/список значений

Нативный реквизит формы, виден пользователю и в отладчике, но требует переделки структуры в табличный вид.

Способ 4. Замена структуры списком или таблицей значений

Часто структуру на форме можно вообще не хранить, а заменить нативным реквизитом. Если структура — это по сути набор пар «имя параметра — значение», её естественное отражение в форме — таблица значений с двумя колонками: ИмяПараметра и Значение. Такой реквизит платформа передаёт между клиентом и сервером штатно, его можно показать пользователю и редактировать интерактивно.

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

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

Способ 5. Динамическое создание реквизитов формы

Если ключи структуры известны на момент открытия формы, можно программно создать по одному реквизиту формы на каждый ключ — методом ИзменитьРеквизиты в обработчике ПриСозданииНаСервере. Каждый ключ становится отдельным типизированным реквизитом, который можно привязать к элементу формы.

&НаСервере

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

Добавляемые = Новый Массив;

Для Каждого КлючЗначение Из СтруктураДанных Цикл

Добавляемые.Добавить(Новый РеквизитФормы(

КлючЗначение.Ключ,

Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(200))));

КонецЦикла;

ИзменитьРеквизиты(Добавляемые);

Для Каждого КлючЗначение Из СтруктураДанных Цикл

ЭтотОбъект[КлючЗначение.Ключ] = Строка(КлючЗначение.Значение);

КонецЦикла;

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

Ограничения существенные: ИзменитьРеквизиты работает только на сервере, имена реквизитов должны быть допустимыми идентификаторами (без пробелов и спецсимволов, не совпадающие с существующими), а повторное изменение состава реквизитов требует аккуратности — удалять и пересоздавать их при каждом обновлении данных дорого. Этот способ оправдан, когда структура — фактически набор редактируемых полей, которые нужно показать пользователю как отдельные элементы формы.

Как выбрать способ за пять шагов
  1. 1
    Определите, нужно ли показывать данные пользователю на форме. Если да — используйте таблицу значений или динамические реквизиты.
  2. 2
    Проверьте, есть ли в структуре ссылки, даты или вложенные объекты. Если есть — выбирайте ЗначениеВСтрокуВнутр или ХранилищеЗначения, а не JSON.
  3. 3
    Оцените частоту обращений: при частом чтении на клиенте берите JSON-строку, чтобы избежать лишних серверных вызовов.
  4. 4
    Решите, нужно ли сохранять данные в базу. Для долговременного хранения используйте JSON или XML, а не внутренний формат платформы.
  5. 5
    Реализуйте пару процедур «упаковать/распаковать» и проверьте их на тестовой структуре с разными типами значений.

Типичные ошибки и как их избежать

Самая частая ошибка — попытка объявить в модуле формы переменную и хранить структуру в ней. В управляемой форме переменные модуля не сохраняются между серверными вызовами: контекст формы пересоздаётся, и структура теряется. Хранить данные между вызовами можно только в реквизитах формы или в параметрах формы.

Вторая ошибка — сериализация ссылок через JSON без учёта потери типа. После обратного чтения ссылка превращается в строку, и код, ожидающий ссылочный тип, падает или молча работает неправильно. Решение — хранить рядом с сериализованным значением информацию о типе или использовать ЗначениеВСтрокуВнутр.

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

Типичные ошибки
01
Хранение структуры в переменной модуля формы — данные теряются при каждом серверном вызове.
02
Сериализация ссылок в JSON — после чтения тип теряется, ссылка становится строкой.
03
Вызов ЗначениеИзСтрокиВнутр на клиенте — метод доступен только на сервере, код не скомпилируется.
04
Долговременное хранение данных в формате ЗначениеВСтрокуВнутр в базе — при обновлении платформы данные могут перестать читаться.
05
Создание динамических реквизитов с именами, содержащими пробелы или кириллические спецсимволы — ошибка при ИзменитьРеквизиты.

Проверка результата и отладка

Проверить корректность упаковки просто: сразу после сохранения структуры в реквизит выполните обратное чтение и сравните количество элементов и значения ключей с исходными. Для JSON-варианта дополнительно откройте значение строкового реквизита в отладчике — строка должна быть читаемым JSON без обрезки. Если реквизит объявлен с ограничением длины, длинная сериализованная структура молча обрежется, и чтение упадёт с ошибкой парсинга.

Признаки проблем при отладке: пустая строка в реквизите после серверного вызова (значит, данные хранились в переменной модуля, а не в реквизите), ошибка «Ошибка формата потока» при ЗначениеИзСтрокиВнутр (строка повреждена или записана другой версией), потеря вложенных структур при JSON-сериализации сложных типов.

Контрольные точки

Как проверить результат

Содержимое строкового реквизита после упаковки
Норма

Читаемый JSON или непустая внутренняя строка

Тревожный признак

Пустая строка или обрезанный фрагмент

Обратное чтение структуры
Норма

Количество ключей совпадает с исходным, типы значений сохранены

Тревожный признак

Меньше элементов, ссылки превратились в строки

Повторный серверный вызов
Норма

Данные в реквизите на месте

Тревожный признак

Реквизит пуст — значит, данные хранились не в реквизите формы

Частые вопросы

Можно ли хранить структуру в параметрах формы?

Да, параметры формы могут быть структурой, если параметр объявлен с произвольным типом или значение передано при открытии через параметры. Но параметры доступны только при создании формы — после открытия обратиться к ним штатно нельзя, поэтому в ПриСозданииНаСервере структуру из параметров обычно сразу переносят в реквизит одним из описанных способов.

Что выбрать: JSON или ЗначениеВСтрокуВнутр?

Если структура содержит только примитивные типы (строки, числа, булево) и нужна переносимость — JSON. Если внутри ссылки, даты, таблицы значений и данные живут только в рамках сеанса работы — ЗначениеВСтрокуВнутр, потому что типы восстановятся точно.

Передаётся ли хранилище значения между клиентом и сервером?

Реквизит типа ХранилищеЗначения сохраняется в данных формы, но работать с ним (помещать и извлекать) можно только на сервере. Для активной клиентской логики удобнее JSON-строка, которую можно читать и на клиенте через сторонние средства или передавать на сервер целиком.

Как хранить вложенную структуру с таблицей значений внутри?

JSON-вариант потребует ручной сериализации таблицы в массив структур. Проще использовать ЗначениеВСтрокуВнутр или ХранилищеЗначения — они упакуют вложенную таблицу значений целиком и восстановят её без дополнительного кода.

Можно ли сохранить сериализованную структуру в базу данных?

Да, но только в переносимом формате — JSON или XML. Строку, полученную через ЗначениеВСтрокуВнутр, сохранять в базу не рекомендуется: внутренний формат может измениться между версиями платформы, и накопленные данные перестанут читаться.

Почему данные из реквизита пропадают после закрытия формы?

Реквизиты формы существуют только пока открыта форма — это временные данные сеанса. Если значения нужны между сеансами, их необходимо сохранять в базу: в реквизит объекта, регистр сведений, константу или в хранилище общих настроек через ХранилищеОбщихНастроек.

Итог

Что важно запомнить

Структура не может быть типом реквизита формы напрямую. Храните её сериализованной: в JSON-строке для простых данных, через ЗначениеВСтрокуВнутр или ХранилищеЗначения — когда важно сохранить типы. Для отображаемых данных заменяйте структуру таблицей значений или динамическими реквизитами. Никогда не храните структуру в переменных модуля управляемой формы — они не переживают серверный вызов.