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

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

Тип «Хранилище значения» в 1С: что это и как с ним работать

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

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

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

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

Что такое хранилище значения и как оно устроено

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

При чтении реквизита типа «Хранилище значения» вы получаете не само значение, а объект-обёртку. Чтобы достать содержимое, нужно явно вызвать метод Получить(). Если хранилище пустое (значение не записывалось), метод вернёт Неопределено — это нужно учитывать в коде, иначе получите ошибку при обращении к свойствам результата.

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

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

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

  • Двоичные данные — содержимое файлов любого формата: документы, архивы, PDF, видео;
  • Картинка — объект типа «Картинка» для отображения изображений в формах;
  • Таблица значений, дерево значений — результаты расчётов, настройки, снимки данных;
  • Структуры и соответствия — наборы настроек, параметры обработок;
  • Результаты запросов, табличные документы — например, сохранённый макет отчёта.

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

Как создать реквизит с типом «Хранилище значения»

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

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

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

Реквизит объекта типа ХранилищеЗначения

Простая реализация для одного-двух файлов на объект. Минус: BLOB читается вместе с объектом, замедляя выборки.

Отдельный регистр сведений или справочник файлов

Подходит для множества файлов и больших объёмов. Чтение по требованию, основная таблица остаётся лёгкой.

Тома хранения файлов на диске

Файлы лежат в каталоге, в базе — только ссылки. Экономит размер базы, но требует настройки и резервного копирования каталога.

Запись и чтение данных: примеры кода

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

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

Объект = СсылкаНаЭлемент.ПолучитьОбъект();

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

Объект.ИмяФайла = "dogovor.pdf";

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

Чтение выполняется обратным образом — через метод Получить() с обязательной проверкой на пустое значение:

Хранилище = Объект.ФайлВложение;

Данные = Хранилище.Получить();

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

// хранилище пустое — файл не был загружен

Иначе

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

КонецЕсли;

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

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

Хранилище значения и временное хранилище: в чём разница

Частая путаница у начинающих разработчиков — смешение хранилища значения и временного хранилища. Это разные механизмы. Хранилище значения — тип данных для постоянного сохранения в базе. Временное хранилище — механизм передачи данных между клиентом и сервером в рамках сеанса, доступный по специальному URL-адресу.

Типичная связка при работе с файлами в управляемых формах: файл помещается с клиента во временное хранилище (ПоместитьФайл или НачатьПомещениеФайла), на сервере извлекается по адресу через ПолучитьИзВременногоХранилища и уже затем упаковывается в хранилище значения для записи в базу. Пропуск промежуточного шага — частая причина ошибок «в файле ничего нет».

Ограничения, производительность и риски

Главное ограничение уже упоминалось: содержимое хранилища не участвует в запросах. Вы не сможете написать условие «ГДЕ ФайлВложение СОДЕРЖИТ...» или найти элементы по данным внутри хранилища. Если такая потребность возникает — выносите поисковые атрибуты в отдельные реквизиты.

Второй риск — рост базы. Сотни мегабайт вложений в таблице справочника увеличивают размер базы, время резервного копирования и регенерационные операции СУБД. Для массового хранения файлов рассмотрите тома на диске или внешние хранилища.

Третий момент — транзакционность. Запись объекта с большим BLOB-полем увеличивает время транзакции и риск блокировок при конкурентной работе. Загружайте тяжёлые вложения вне пиковой нагрузки и по возможности порционно.

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

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

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

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

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

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

Возвращает объект ожидаемого типа (ДвоичныеДанные, Картинка)

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

Возвращает Неопределено — запись не выполнилась или читается другой реквизит

Извлечённый файл
Норма

Открывается в штатной программе, размер совпадает с оригиналом

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

Файл нулевого размера или не открывается — ошибка в цепочке передачи данных

Скорость выборки списка
Норма

Список открывается без заметной задержки

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

Замедление — BLOB читается вместе со списком, нужно выносить файлы в отдельную таблицу

Часто задаваемые вопросы

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

Напрямую по содержимому — нет. Но можно проверить факт заполнения: в запросе сравнить реквизит со значением по умолчанию или программно перебрать элементы и вызвать Получить(). Для больших таблиц перебор с извлечением BLOB медленный, поэтому часто добавляют отдельный булев реквизит «ЕстьФайл», который заполняется при записи.

Чем хранилище значения отличается от строки неограниченной длины?

Строка неограниченной длины хранит только текст и доступна для поиска по подстроке (с ограничениями СУБД). Хранилище значения хранит сериализованный объект любого типа, включая двоичные данные, но полностью непрозрачно для запросов. Текст в хранилище класть можно, но смысла в этом обычно нет.

Можно ли хранить в хранилище значения ссылку на другой объект базы?

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

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

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

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

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

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

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

Итог

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

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