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

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

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

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

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

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

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

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

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

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

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

Как записать значение в хранилище

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

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

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

НовыйОбъект.Наименование = "Прайс-лист";

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

НовыйОбъект.Записать();

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

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

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

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

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ ХранилищеФайла ИЗ Справочник.Файлы ГДЕ Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", СсылкаНаФайл);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

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

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

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

КонецЕсли;

КонецЕсли;

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

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

Что можно и нельзя хранить

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

Что хранимПодходит лиОсобенности
ДвоичныеДанные (файлы)ДаСтандартный способ хранения файлов в базе; большие файлы раздувают базу
КартинкаДаИспользуется для изображений товаров, логотипов
ТаблицаЗначений, ДеревоЗначенийДаУдобно для сохранения результатов расчётов и настроек
Структура, Соответствие, МассивДаЭлементы внутри тоже должны быть сериализуемыми
Строка неограниченной длины, XMLДа, но избыточноДля текста часто проще использовать строковый реквизит
Ссылки на объекты базыТехнически да, с оговоркамиХранится сериализованное представление; для ссылок используйте обычные ссылочные реквизиты
COM-объекты, открытые формыНетНе сериализуются, вызовут ошибку

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

Хранилище значения в запросах и СКД

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

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

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

Производительность и размер базы

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

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

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

Альтернативы хранилищу значения

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

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

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

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

Объекты платформы, файлы, картинки. Минус: не читается запросом, раздувает базу

Строка неограниченной длины

Тексты, XML, JSON. Плюс: доступна в запросах и отчётах. Минус: только текст

Внешние тома (файлы на диске)

Большие файлы. Плюс: база не растёт. Минус: нужно администрировать доступность томов и бэкапы отдельно

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

Как проверить, пустое ли хранилище значения?

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

Можно ли вывести содержимое хранилища в отчёт на СКД?

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

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

Метод вернёт Неопределено. Это штатная ситуация, а не ошибка, поэтому перед использованием результата всегда делайте проверку, иначе обращение к свойствам или методам результата завершится исключением.

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

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

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

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

Как узнать, какие таблицы с хранилищами занимают больше всего места?

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

Итог

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

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