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

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

Как сохранить таблицу значений в хранилище в 1С

Как сохранить таблицу значений в хранилище значения в 1С: сериализация через ЗначениеВСтрокуВнутр, ХранилищеЗначения, примеры кода, ошибки и проверка результата.

Таблица значений в 1С — объект, который существует только в оперативной памяти сеанса. Напрямую записать её в реквизит объекта нельзя: тип «ТаблицаЗначений» не входит в список типов, допустимых для реквизитов метаданных. Поэтому для передачи таблицы между сеансами, сохранения её между запусками или передачи в фоновое задание используют промежуточные механизмы — чаще всего хранилище значения (ХранилищеЗначения) или сериализацию в строку.

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

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

Как сохранить таблицу значений в реквизит типа «ХранилищеЗначения»

Базовый сценарий: в справочнике или документе создан реквизит с типом «ХранилищеЗначения» (например, ДанныеТаблицы). Чтобы положить туда таблицу, её передают в конструктор хранилища и записывают объект.

ТЗ = Новый ТаблицаЗначений;

ТЗ.Колонки.Добавить("Номенклатура");

ТЗ.Колонки.Добавить("Количество");

НоваяСтрока = ТЗ.Добавить();

НоваяСтрока.Номенклатура = "Товар 1";

НоваяСтрока.Количество = 5;

ОбъектСпр = Справочники.Настройки.СоздатьЭлемент();

ОбъектСпр.Наименование = "Сохранённая таблица";

ОбъектСпр.ДанныеТаблицы = Новый ХранилищеЗначения(ТЗ, Новый СжатиеДанных(9));

ОбъектСпр.Записать();

Второй параметр конструктора — Новый СжатиеДанных(9) — включает сжатие данных внутри хранилища. Для больших таблиц это заметно уменьшает объём в базе, но чуть замедляет запись и чтение. Если таблица небольшая, параметр можно опустить.

Обратное чтение выполняется методом Получить(), который возвращает сохранённое значение:

ТЗ = ОбъектСпр.ДанныеТаблицы.Получить();

Если ТипЗнч(ТЗ) = Тип("ТаблицаЗначений") Тогда

Для Каждого Строка Из ТЗ Цикл

Сообщить(Строка.Номенклатура);

КонецЦикла;

КонецЕсли;

Сохранение через ЗначениеВСтрокуВнутр — когда хранилище недоступно

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

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

ОбъектСпр.СериализованныеДанные = СтрокаДанных;

ОбъектСпр.Записать();

// обратное чтение

ТЗ = ЗначениеИзСтрокиВнутр(ОбъектСпр.СериализованныеДанные);

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

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

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

Оптимально для хранения внутри одной базы. Поддерживает сжатие, не читается внешними системами.

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

Подходит, когда нужен строковый реквизит или передача между базами 1С. Не читается не-1С системами.

Массив структур + JSON

Универсальный обмен с внешними системами и веб-сервисами. Требует ручного преобразования колонок и типов.

Сохранение таблицы через JSON для обмена с внешними системами

Когда таблицу нужно отдать в HTTP-сервис, файл или другую программу, её преобразуют в массив структур и записывают в JSON. Платформа не сериализует ТаблицуЗначений в JSON напрямую, поэтому требуется промежуточное преобразование.

МассивСтрок = Новый Массив;

Для Каждого СтрокаТЗ Из ТЗ Цикл

СтруктураСтроки = Новый Структура;

Для Каждого Колонка Из ТЗ.Колонки Цикл

СтруктураСтроки.Вставить(Колонка.Имя, СтрокаТЗ[Колонка.Имя]);

КонецЦикла;

МассивСтрок.Добавить(СтруктураСтроки);

КонецЦикла;

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

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

ЗаписатьJSON(Запись, МассивСтрок);

СтрокаJSON = Запись.Закрыть();

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

Хранение таблицы в реквизите формы и временном хранилище

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

АдресХранилища = ПоместитьВоВременноеХранилище(ТЗ, ЭтаФорма.УникальныйИдентификатор);

// ... передача адреса в другую форму или фоновое задание

ТЗ = ПолучитьИзВременногоХранилища(АдресХранилища);

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

Типичные ошибки при сохранении и чтении

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

Типичные ошибки
01
Присвоение таблицы реквизиту напрямую без конструктора ХранилищеЗначения — ошибка несоответствия типов при записи объекта.
02
Чтение через Получить() без проверки типа — падение кода, если хранилище ещё не заполнялось.
03
Хранение таблицы с колонками несериализуемых типов (например, элементы формы, COM-объекты) — исключение при сериализации.
04
Использование строкового реквизита фиксированной длины для ЗначениеВСтрокуВнутр — данные обрезаются и не восстанавливаются.
05
Ожидание, что JSON восстановит ссылки на объекты базы — в JSON остаются только строковые представления.

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

Как проверить, что данные сохранились корректно

После записи объекта полезно выполнить контрольное чтение в той же транзакции или сразу после неё: получить таблицу из хранилища и сравнить количество строк и колонок с исходной. Это дешёвая проверка, которая отлавливает обрезание данных и ошибки сериализации.

СохраненнаяТЗ = ОбъектСпр.ДанныеТаблицы.Получить();

Если СохраненнаяТЗ = Неопределено Тогда

ВызватьИсключение "Хранилище пустое после записи";

КонецЕсли;

Если СохраненнаяТЗ.Количество() <> ТЗ.Количество() Тогда

ВызватьИсключение "Количество строк не совпадает";

КонецЕсли;

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

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

Тип результата Получить()
Норма

ТаблицаЗначений

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

Неопределено или Строка — хранилище пустое или заполнено другим значением

Количество строк
Норма

Совпадает с исходной таблицей

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

Меньше исходного — данные обрезаны или сериализация прервалась

Значения ссылочных колонок
Норма

Ссылки открываются, реквизиты доступны

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

Битые ссылки или строки вместо ссылок — данные прошли через JSON или текстовый формат

Что выбрать в конкретной ситуации

Маршрут решения

Как выбрать способ

Таблица хранится и читается только внутри одной базы 1СИспользуйте реквизит типа ХранилищеЗначения со сжатием
Нужно передать таблицу в другую базу 1С текстом или файломСериализуйте через ЗначениеВСтрокуВнутр и сохраняйте в неограниченную строку
Данные уходят во внешнюю систему, API или файл обменаПреобразуйте таблицу в массив структур и запишите в JSON
Таблица нужна только на время работы формы или фонового заданияИспользуйте временное хранилище через ПоместитьВоВременноеХранилище
Данные табличные по смыслу и регулярно запрашиваются отчётамиОткажитесь от сериализации — храните данные в табличной части или регистре сведений

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

Итог

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

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

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

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

Напрямую — нет, но обычно это и не требуется: табличная часть сама по сути является таблицей. Таблицу значений переносят в табличную часть методом Загрузить(): Объект.Товары.Загрузить(ТЗ). Колонки сопоставляются по именам, лишние колонки игнорируются.

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

Чаще всего причина в том, что в хранилище поместили пустую таблицу или записали объект до заполнения таблицы. Проверьте порядок операторов: конструктор хранилища фиксирует состояние таблицы на момент вызова, последующие добавления строк в переменную на сохранённую копию не влияют.

Можно ли хранить в ХранилищеЗначения несколько таблиц сразу?

Да. Поместите таблицы в структуру или массив и передайте эту структуру в конструктор хранилища: Новый ХранилищеЗначения(Новый Структура("ТЗ1, ТЗ2", Таблица1, Таблица2)). При чтении Получить() вернёт структуру, из которой таблицы извлекаются по ключам.

Влияет ли сжатие данных на скорость работы?

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

Как передать таблицу значений в фоновое задание?

Параметры фонового задания сериализуются, поэтому таблицу можно передать напрямую в массиве параметров метода ФоновыеЗадания.Выполнить(). Альтернатива — поместить таблицу во временное хранилище и передать в задание только адрес, что эффективнее для больших объёмов.

Откроется ли сохранённая таблица после обновления конфигурации?

Хранилище значения сериализует данные, а не метаданные, поэтому сама таблица откроется. Но если в колонках хранились ссылки на удалённые при обновлении объекты метаданных, при обращении к ним возникнут битые ссылки. Перед удалением объектов конфигурации проверьте, не хранятся ли на них ссылки в сериализованных данных.