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

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

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

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

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

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

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

Что можно хранить и как устроен механизм

В хранилище значений допустимо помещать практически любые данные, которые платформа умеет сериализовать. Чаще всего там оказываются двоичные данные файлов, объекты типа Картинка, таблицы значений, деревья значений, структуры, массивы, результаты запросов и настройки компоновки данных.

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

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

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

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

// Сохранение картинки в реквизит справочника

ДвоичныеДанные = Новый ДвоичныеДанные("C:\Images\tovar.jpg");

ТоварОбъект = Справочники.Номенклатура.НайтиПоКоду("000001").ПолучитьОбъект();

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

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

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

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

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

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

ТоварСсылка = Справочники.Номенклатура.НайтиПоКоду("000001");

Хранилище = ТоварСсылка.ФотоТовара;

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

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

Сообщить("Изображение не задано");

Иначе

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

КонецЕсли;

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

Где хранилище значений применяется на практике

Самые распространённые сценарии в типовых и самописных конфигурациях:

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

    Куда складывать данные

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

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

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

    Подходит, если по данным нужен поиск, отборы и отчёты. Ограничение: структура должна быть заранее известна.

    Внешнее файловое хранилище

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

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

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

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

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

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

    Как проверить, что всё работает правильно

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

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

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

    Значение реквизита после записи
    Норма

    Реквизит заполнен, Получить() возвращает объект нужного типа

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

    Получить() возвращает Неопределено или другой тип

    Размер сохранённых данных
    Норма

    Совпадает с размером исходного файла или близок к нему

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

    Нулевой размер или сильное расхождение

    Повторное открытие в новом сеансе
    Норма

    Данные доступны и читаются без ошибок

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

    Ошибка десериализации — вероятно, повреждена запись или изменилась структура

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

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

    Частые вопросы о хранилище значений

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

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

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

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

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

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

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

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

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

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

    Как очистить устаревшие данные из хранилищ?

    Напишите сервисную обработку: найдите записи по критерию устаревания (например, по дате), установите реквизит в пустое значение или удалите сами записи, затем выполните регламентные операции сжатия таблиц на уровне СУБД, если база клиент-серверная.

    Итог

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

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