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