Разработка и Конфигурация · 11 мин
Как поместить данные в хранилище значений в 1С
Как поместить данные в хранилище значений 1С: конструктор, методы ПоместитьВоВременноеХранилище, сжатие, примеры кода и типичные ошибки разработчика.
Хранилище значения (тип ХранилищеЗначения) — универсальный контейнер встроенного языка 1С, который позволяет сохранить практически любые данные: строки, таблицы значений, картинки, двоичные данные, результаты запросов и даже сериализуемые объекты. Чаще всего его применяют для реквизитов справочников и документов, когда нужно хранить в базе файлы, изображения или настройки сложной структуры.
Механизм работает в две стороны: методом Новый ХранилищеЗначения(Данные) данные упаковываются и записываются в базу, а методом Получить() извлекаются обратно в исходном виде. Важно понимать, что внутри хранилища данные сериализуются, поэтому ссылочные объекты базы (элементы справочников, документы) сохранить напрямую нельзя — только их представления или значения простых типов.
Ниже разобраны практические сценарии: создание хранилища с сжатием и без, работа с временным хранилищем формы, запись файлов и картинок в реквизиты, проверка результата и ошибки, которые чаще всего приводят к потере данных или росту базы.
Что такое хранилище значения и когда его применять
Хранилище значения — это объектная обёртка, которая сериализует переданные данные во внутренний формат платформы. В базе данных такой реквизит хранится как BLOB-поле. Платформа сама заботится о преобразовании, разработчику доступны только две операции: упаковать и распаковать.
Типичные сценарии использования: хранение фотографий товаров в справочнике «Номенклатура», сохранение сканов документов, архивирование печатных форм в формате табличного документа, хранение настроек обменов в виде структур или таблиц значений, логирование текстов запросов и ответов веб-сервисов.
Хранилище не подходит для данных, по которым нужно искать или строить отчёты: содержимое BLOB-поля недоступно запросам. Если по значению требуется отбор, сортировка или группировка — заводите обычные реквизиты, а хранилище используйте только для «тяжёлого» вложения.
Базовый синтаксис: конструктор и метод Получить
Создание хранилища выполняется конструктором. Второй параметр — степень сжатия (объект СжатиеДанных), он необязателен:
// Простая упаковка строки
Хранилище = Новый ХранилищеЗначения("Текст для сохранения");
// Упаковка таблицы значений со сжатием
Хранилище = Новый ХранилищеЗначения(ТаблицаДанных, Новый СжатиеДанных(9));
// Запись в реквизит объекта
ОбъектСправочника.ДанныеВложения = Хранилище;
ОбъектСправочника.Записать();
Извлечение выполняется методом Получить(). Если реквизит пуст, метод вернёт Неопределено, поэтому результат всегда стоит проверять перед использованием:
Данные = ОбъектСправочника.ДанныеВложения.Получить();
Если Данные = Неопределено Тогда
// хранилище пустое — обработать ситуацию
КонецЕсли;
Какие типы данных можно поместить
Платформа допускает сериализацию большинства типов встроенного языка, но есть жёсткое ограничение: объекты, привязанные к базе данных (СправочникОбъект, ДокументОбъект и подобные), в хранилище поместить нельзя. Ссылки на объекты — можно, они сохраняются как значения.
| Тип данных | Можно ли поместить | Комментарий |
|---|---|---|
| Строка, Число, Дата, Булево | Да | Простейший случай, проблем не бывает |
| ТаблицаЗначений, ДеревоЗначений | Да | Рекомендуется сжатие при большом объёме |
| Структура, Соответствие, Массив | Да | Вложенные коллекции тоже сериализуются |
| ДвоичныеДанные, Картинка | Да | Основной сценарий для файлов и изображений |
| ТабличныйДокумент | Да | Удобно для архива печатных форм |
| Ссылки на объекты базы | Да | Сохраняется ссылка, а не объект |
| СправочникОбъект, ДокументОбъект | Нет | Вызовет ошибку сериализации |
| Запрос, ПостроительОтчета | Нет | Сохраняйте текст запроса и параметры отдельно |
Если нужно сохранить настройки, включающие ссылки (например, отборы с элементами справочников), соберите их в структуру или таблицу значений — ссылки внутри коллекций сериализуются корректно.
Сжатие данных: когда оно оправдано
Второй параметр конструктора принимает объект СжатиеДанных со степенью от 1 (быстрое сжатие) до 9 (максимальное). Сжатие уменьшает размер BLOB-поля в базе, но требует процессорного времени при записи и чтении.
Практическое правило: текстовые данные (XML, JSON, тексты запросов, таблицы значений) сжимаются хорошо, иногда в несколько раз, поэтому сжатие для них почти всегда оправдано. Уже сжатые форматы — JPEG, PNG, ZIP-архивы, PDF — при повторном сжатии почти не уменьшаются, а время на упаковку тратится.
Как выбрать действие
Запись файлов и картинок в реквизит справочника
Самый частый прикладной сценарий — сохранить файл с диска в реквизит типа ХранилищеЗначения. Файл читается в двоичные данные, затем упаковывается:
ДвоичныеДанные = Новый ДвоичныеДанные("C:\Files\scan.pdf");
Объект = Справочники.ПрисоединенныеФайлы.СоздатьЭлемент();
Объект.Наименование = "Скан договора";
Объект.ХранилищеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
Объект.Записать();
Обратная операция — извлечение и сохранение на диск:
ДвоичныеДанные = Объект.ХранилищеФайла.Получить();
Если ДвоичныеДанные <> Неопределено Тогда
ДвоичныеДанные.Записать("C:\Temp\scan.pdf");
КонецЕсли;
Для изображений вместо двоичных данных можно использовать объект Картинка — он дополнительно хранит сведения о формате, что упрощает вывод в форму. Но по объёму разницы почти нет, поэтому выбор — вопрос удобства дальнейшей работы.
Временное хранилище формы: ПоместитьВоВременноеХранилище
Отдельный механизм — временное хранилище, которое связывает данные с формой или сеансом. Оно нужно для передачи данных между клиентом и сервером, например при загрузке файла в управляемой форме или передаче результата из длительной фоновой операции.
// На сервере: поместить данные и получить адрес
Адрес = ПоместитьВоВременноеХранилище(ТаблицаРезультата, УникальныйИдентификаторФормы);
// Позже: извлечь по адресу
Данные = ПолучитьИзВременногоХранилища(Адрес);
// Когда данные больше не нужны
УдалитьИзВременногоХранилища(Адрес);
Если передать вторым параметром УникальныйИдентификатор формы, данные живут, пока открыта форма, и удаляются автоматически при её закрытии. Без идентификатора хранилище живёт до конца сеанса — при массовых операциях это приводит к накоплению мусора в памяти сервера, поэтому адрес без привязки к форме нужно очищать вручную.
- 1На клиенте вызовите НачатьПомещениеФайла и получите адрес временного хранилища
- 2Передайте адрес в серверную процедуру формы
- 3На сервере получите данные через ПолучитьИзВременногоХранилища(Адрес)
- 4Упакуйте данные в Новый ХранилищеЗначения и запишите в реквизит объекта
- 5Удалите данные из временного хранилища, если оно не привязано к форме
Проверка результата и типичные ошибки
После записи убедитесь, что данные действительно в базе: перечитайте объект и вызовите Получить(). Для оценки объёма можно сериализовать значение в строку XML через ЗначениеВСтрокуВнутр и посмотреть длину — это грубый, но быстрый способ понять, насколько разрослось хранилище.
Как проверить результат
Возвращает данные исходного типа
Возвращает Неопределено — объект не записан или реквизит не заполнен
Совпадает с типом упакованного (ТаблицаЗначений, ДвоичныеДанные и т.д.)
Тип отличается — вероятно, записаны другие данные или читается не тот реквизит
Рост соответствует суммарному объёму вложений
База растёт кратно быстрее — проверьте дублирование записей и отсутствие сжатия
Ещё одна частая проблема — попытка прочитать хранилище в запросе. Конструкция ВЫБРАТЬ Товары.Фото вернёт значение типа ХранилищеЗначения, и вызвать Получить() можно только после выборки, в коде. В СКД для картинок используют вычисляемые поля или функции общих модулей.
Что важно запомнить
Данные упаковываются конструктором Новый ХранилищеЗначения(Значение, Сжатие) и извлекаются методом Получить(). Ссылочные объекты базы сериализовать нельзя — только ссылки и коллекции. Для обмена между клиентом и сервером в формах используйте временное хранилище и не забывайте его очищать.
Частые вопросы
Можно ли поместить в хранилище результат запроса?
Напрямую объект Запрос или РезультатЗапроса сериализовать нельзя. Выполните запрос, выгрузите результат в таблицу значений методом Выгрузить() и упакуйте уже её — таблица значений сериализуется без ограничений.
Как очистить реквизит типа ХранилищеЗначения?
Присвойте реквизиту пустое значение: Объект.ХранилищеФайла = Неопределено и запишите объект. После этого Получить() будет возвращать Неопределено, а место в базе освободится после сжатия таблиц СУБД.
Чем хранилище значения отличается от временного хранилища?
Хранилище значения — тип данных для постоянной записи в реквизиты базы. Временное хранилище — механизм сеанса для передачи данных между клиентом и сервером по адресу; оно не сохраняется в базе и уничтожается при закрытии формы или сеанса.
Почему после Получить() я получаю Неопределено, хотя данные записывал?
Чаще всего объект не был записан после присвоения реквизита, либо читается другой объект или другой реквизит. Также проверьте, что упаковывалось непустое значение: Новый ХранилищеЗначения(Неопределено) при чтении даст Неопределено.
Можно ли искать по содержимому хранилища запросом?
Нет. Содержимое BLOB-поля недоступно ни в запросах, ни в СКД. Если по данным нужны отборы, продублируйте ключевые поля в обычные реквизиты объекта, а в хранилище помещайте только полный массив данных.
Как передать содержимое хранилища в другую базу?
Извлеките значение методом Получить(), сериализуйте его (например, через ЗначениеВСтрокуВнутр или преобразование в XML/JSON для простых коллекций) и передайте строку. В приёмнике восстановите значение и при необходимости снова упакуйте в хранилище.