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

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

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

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

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

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

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

Что такое хранилище значения и когда его применять

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

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

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

Базовый синтаксис: конструктор и метод Получить

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

// Простая упаковка строки

Хранилище = Новый ХранилищеЗначения("Текст для сохранения");

// Упаковка таблицы значений со сжатием

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

// Запись в реквизит объекта

ОбъектСправочника.ДанныеВложения = Хранилище;

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

Извлечение выполняется методом Получить(). Если реквизит пуст, метод вернёт Неопределено, поэтому результат всегда стоит проверять перед использованием:

Данные = ОбъектСправочника.ДанныеВложения.Получить();

Если Данные = Неопределено Тогда

// хранилище пустое — обработать ситуацию

КонецЕсли;

Какие типы данных можно поместить

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

Тип данныхМожно ли поместитьКомментарий
Строка, Число, Дата, БулевоДаПростейший случай, проблем не бывает
ТаблицаЗначений, ДеревоЗначенийДаРекомендуется сжатие при большом объёме
Структура, Соответствие, МассивДаВложенные коллекции тоже сериализуются
ДвоичныеДанные, КартинкаДаОсновной сценарий для файлов и изображений
ТабличныйДокументДаУдобно для архива печатных форм
Ссылки на объекты базыДаСохраняется ссылка, а не объект
СправочникОбъект, ДокументОбъектНетВызовет ошибку сериализации
Запрос, ПостроительОтчетаНетСохраняйте текст запроса и параметры отдельно

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

Сжатие данных: когда оно оправдано

Второй параметр конструктора принимает объект СжатиеДанных со степенью от 1 (быстрое сжатие) до 9 (максимальное). Сжатие уменьшает размер BLOB-поля в базе, но требует процессорного времени при записи и чтении.

Практическое правило: текстовые данные (XML, JSON, тексты запросов, таблицы значений) сжимаются хорошо, иногда в несколько раз, поэтому сжатие для них почти всегда оправдано. Уже сжатые форматы — JPEG, PNG, ZIP-архивы, PDF — при повторном сжатии почти не уменьшаются, а время на упаковку тратится.

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

Как выбрать действие

Сохраняете таблицу значений, XML или длинный текстИспользуйте Новый СжатиеДанных(9) — объём заметно уменьшится
Сохраняете картинки JPEG/PNG или PDFСжатие не применяйте — файлы уже сжаты, выигрыша не будет
Данные читаются очень часто, а размер небольшойОткажитесь от сжатия ради скорости чтения

Запись файлов и картинок в реквизит справочника

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

ДвоичныеДанные = Новый ДвоичныеДанные("C:\Files\scan.pdf");

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

Объект.Наименование = "Скан договора";

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

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

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

ДвоичныеДанные = Объект.ХранилищеФайла.Получить();

Если ДвоичныеДанные <> Неопределено Тогда

ДвоичныеДанные.Записать("C:\Temp\scan.pdf");

КонецЕсли;

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

Временное хранилище формы: ПоместитьВоВременноеХранилище

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

// На сервере: поместить данные и получить адрес

Адрес = ПоместитьВоВременноеХранилище(ТаблицаРезультата, УникальныйИдентификаторФормы);

// Позже: извлечь по адресу

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

// Когда данные больше не нужны

УдалитьИзВременногоХранилища(Адрес);

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

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

Проверка результата и типичные ошибки

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

Типичные ошибки
01
Попытка поместить СправочникОбъект вместо ссылки — ошибка сериализации при записи
02
Изменение таблицы после Получить() без повторной записи объекта — изменения теряются
03
Отсутствие проверки на Неопределено после Получить() — падение кода на пустом реквизите
04
Помещение во временное хранилище без идентификатора формы без последующей очистки — утечка памяти сеанса
05
Сжатие уже сжатых файлов (JPEG, ZIP) — лишняя нагрузка без выигрыша в размере
06
Хранение данных, по которым нужны отборы в запросах — содержимое BLOB недоступно СКД и запросам
Контрольные точки

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

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

Возвращает данные исходного типа

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

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

Тип извлечённого значения
Норма

Совпадает с типом упакованного (ТаблицаЗначений, ДвоичныеДанные и т.д.)

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

Тип отличается — вероятно, записаны другие данные или читается не тот реквизит

Размер базы после массовой загрузки файлов
Норма

Рост соответствует суммарному объёму вложений

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

База растёт кратно быстрее — проверьте дублирование записей и отсутствие сжатия

Ещё одна частая проблема — попытка прочитать хранилище в запросе. Конструкция ВЫБРАТЬ Товары.Фото вернёт значение типа ХранилищеЗначения, и вызвать Получить() можно только после выборки, в коде. В СКД для картинок используют вычисляемые поля или функции общих модулей.

Итог

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

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

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

Можно ли поместить в хранилище результат запроса?

Напрямую объект Запрос или РезультатЗапроса сериализовать нельзя. Выполните запрос, выгрузите результат в таблицу значений методом Выгрузить() и упакуйте уже её — таблица значений сериализуется без ограничений.

Как очистить реквизит типа ХранилищеЗначения?

Присвойте реквизиту пустое значение: Объект.ХранилищеФайла = Неопределено и запишите объект. После этого Получить() будет возвращать Неопределено, а место в базе освободится после сжатия таблиц СУБД.

Чем хранилище значения отличается от временного хранилища?

Хранилище значения — тип данных для постоянной записи в реквизиты базы. Временное хранилище — механизм сеанса для передачи данных между клиентом и сервером по адресу; оно не сохраняется в базе и уничтожается при закрытии формы или сеанса.

Почему после Получить() я получаю Неопределено, хотя данные записывал?

Чаще всего объект не был записан после присвоения реквизита, либо читается другой объект или другой реквизит. Также проверьте, что упаковывалось непустое значение: Новый ХранилищеЗначения(Неопределено) при чтении даст Неопределено.

Можно ли искать по содержимому хранилища запросом?

Нет. Содержимое BLOB-поля недоступно ни в запросах, ни в СКД. Если по данным нужны отборы, продублируйте ключевые поля в обычные реквизиты объекта, а в хранилище помещайте только полный массив данных.

Как передать содержимое хранилища в другую базу?

Извлеките значение методом Получить(), сериализуйте его (например, через ЗначениеВСтрокуВнутр или преобразование в XML/JSON для простых коллекций) и передайте строку. В приёмнике восстановите значение и при необходимости снова упакуйте в хранилище.