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

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

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

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

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

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

Что такое хранилище значений и когда оно нужно

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

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

Базовый код: упаковка и распаковка таблицы

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

// Формируем таблицу

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

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

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

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

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

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

// Упаковка в хранилище

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

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

// Обратное извлечение

ВосстановленнаяТаблица = Объект.ДанныеТаблицы.Получить();

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

// работаем с таблицей

КонецЕсли;

Обратите внимание на проверку типа после Получить(). Если реквизит не был заполнен, метод вернёт Неопределено, и обращение к методам таблицы вызовет ошибку. Проверка типа — обязательный элемент устойчивого кода.

Подготовка конфигурации: куда сохранять хранилище

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

Для пользовательских настроек удобен регистр сведений с измерением «Пользователь» и ресурсом типа ХранилищеЗначения. Для данных, привязанных к конкретному документу, — реквизит самого документа. Константа подходит только для единственного глобального значения.

Порядок действий
  1. 1
    Добавьте в объект метаданных реквизит с типом ХранилищеЗначения
  2. 2
    В коде сформируйте таблицу значений и наполните её
  3. 3
    Присвойте реквизиту значение Новый ХранилищеЗначения(Таблица)
  4. 4
    Запишите объект или набор записей
  5. 5
    При чтении вызовите Получить() и проверьте тип результата

Передача таблицы между сеансами без записи в базу

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

// Сериализация в строку

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

// Десериализация

ВосстановленнаяТаблица = ЗначениеИзСтрокиВнутр(СтрокаДанных);

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

Сравнение вариантов

ХранилищеЗначения в реквизите

Постоянное хранение в базе; недоступно для запросов, данные читаются только целиком

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

Передача между сеансами и хранение в строковых полях; строка объёмная, формат внутренний

Временное хранилище формы

Обмен клиент–сервер в рамках сеанса; данные живут ограниченное время и не попадают в базу

Регистр сведений / табличная часть

Когда по данным нужны отборы, соединения и отчёты; требует нормализованной структуры

Ограничения и типичные ошибки

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

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

Третья ошибка — хранение таблицы со ссылками на объекты, которые потом удаляют. Ссылки внутри сериализованной таблицы не контролируются механизмом ссылочной целостности: после удаления объекта в восстановленной таблице останутся «битые» ссылки.

Типичные ошибки
01
Забыть проверить тип после Получить() — при пустом реквизите получают ошибку обращения к Неопределено
02
Хранить большие таблицы без сжатия — база растёт, чтение объекта тормозит
03
Пытаться использовать содержимое хранилища в запросе — технически невозможно, нужно менять архитектуру
04
Сохранять таблицу с ссылками на удаляемые объекты — ссылочная целостность не контролируется
05
Смешивать версии структуры таблицы — старые записи с другим набором колонок ломают код чтения

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

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

При изменении структуры таблицы (добавлении колонок) старые записи в базе сохранят прежнюю структуру. Предусмотрите в коде чтения обработку отсутствующих колонок или выполните разовое пересохранение данных.

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

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

Вызов Получить() после записи
Норма

Возвращается объект типа ТаблицаЗначений

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

Возвращается Неопределено — реквизит не был заполнен или объект не записан

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

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

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

Отличается — записана другая таблица или читается не тот реквизит

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

Ссылки доступны, у них есть актуальные данные

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

Битые ссылки — объекты были удалены после сохранения

Когда хранилище значений — неправильный выбор

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

Итог

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

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

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

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

Да. Сериализация сохраняет и структуру колонок, и типы значений в ячейках, включая составные типы. После Получить() таблица восстанавливается с исходным описанием колонок.

Что вернёт Получить(), если реквизит пустой?

Метод вернёт Неопределено. Поэтому перед работой с результатом всегда проверяйте его через ТипЗнч() — иначе обращение к методам таблицы завершится ошибкой исполнения.

Можно ли обновить часть таблицы внутри хранилища?

Нет. Хранилище значений — неделимое поле. Чтобы изменить данные, нужно извлечь таблицу целиком, модифицировать её и записать новое хранилище поверх старого.

Сохраняются ли итоги и индексы таблицы значений?

Индексы, созданные методом Индексы.Добавить(), не сериализуются — после восстановления их нужно создавать заново. Структура колонок и данные строк сохраняются полностью.

Чем сжатие данных влияет на работу с хранилищем?

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

Можно ли поместить в хранилище таблицу вместе с другими данными?

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