Разработка и Конфигурация · 10 мин
Хранилище значений в 1С: что это и как с ним работать
Хранилище значений в 1С — что это, зачем нужно, как сохранить и получить данные, где применяется. Примеры кода, ограничения, типичные ошибки и ответы на вопросы.
Хранилище значений в 1С — это специальный тип данных, который позволяет сохранять в базе практически любые объекты: картинки, файлы, таблицы значений, настройки отчётов, произвольные структуры данных. В конфигураторе он встречается повсюду: в реквизитах справочников, документов, регистров сведений, а в коде представлен объектом ХранилищеЗначения (ValueStorage).
Главная особенность этого типа — внутри него данные хранятся в сериализованном виде, то есть преобразованы в последовательность байт. Платформа «упаковывает» объект при записи и «распаковывает» при чтении. Благодаря этому в одном поле базы данных можно держать содержимое, которое иначе потребовало бы отдельных таблиц или внешних файлов.
Типичная ситуация: нужно прикрепить фотографию товара к карточке номенклатуры или сохранить пользовательские настройки отчёта между сеансами. Именно для таких задач и создан механизм хранилища значений — он встроен в платформу и не требует внешних компонент.
Что можно хранить и как устроен механизм
В хранилище значений допустимо помещать практически любые данные, которые платформа умеет сериализовать. Чаще всего там оказываются двоичные данные файлов, объекты типа Картинка, таблицы значений, деревья значений, структуры, массивы, результаты запросов и настройки компоновки данных.
При записи платформа преобразует объект во внутренний формат и сохраняет его в поле типа «Хранилище значения» в таблице базы данных. Физически это BLOB-поле (в терминах СУБД). При чтении вызывается метод Получить(), который выполняет обратное преобразование — десериализацию — и возвращает исходный объект.
Важно понимать: содержимое хранилища нельзя использовать в запросах для сравнения, фильтрации или поиска по содержимому. Запрос «видит» только факт наличия значения, но не его внутренности. Если по данным нужно искать — хранилище значений не подходит, нужны обычные реквизиты или отдельные регистры.
Как создать и записать значение в хранилище
Создание объекта выполняется конструктором Новый ХранилищеЗначения(Значение). В параметр передаётся то, что нужно сохранить. Результат присваивается реквизиту объекта, у которого в конфигураторе задан тип «ХранилищеЗначения».
// Сохранение картинки в реквизит справочника
ДвоичныеДанные = Новый ДвоичныеДанные("C:\Images\tovar.jpg");
ТоварОбъект = Справочники.Номенклатура.НайтиПоКоду("000001").ПолучитьОбъект();
ТоварОбъект.ФотоТовара = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
ТоварОбъект.Записать();
Второй необязательный параметр конструктора — степень сжатия данных. Сжатие уменьшает объём в базе, но тратит процессорное время при записи и чтении. Для уже сжатых форматов (JPEG, ZIP) дополнительное сжатие почти не даёт выигрыша, а вот для таблиц значений и текстовых настроек оно заметно сокращает размер.
- 1Убедитесь, что у реквизита объекта в конфигураторе установлен тип ХранилищеЗначения
- 2Получите содержимое файла через объект ДвоичныеДанные или подготовьте нужное значение
- 3Создайте объект: Новый ХранилищеЗначения(Значение)
- 4Присвойте результат реквизиту объекта и запишите объект
- 5Проверьте, что реквизит заполнен и значение извлекается без ошибок
Как прочитать данные из хранилища
Извлечение выполняется методом Получить(). Он возвращает значение в исходном типе: если клали картинку — вернётся объект Картинка, если таблицу значений — таблица. Если реквизит пустой, метод вернёт Неопределено.
ТоварСсылка = Справочники.Номенклатура.НайтиПоКоду("000001");
Хранилище = ТоварСсылка.ФотоТовара;
Данные = Хранилище.Получить();
Если Данные = Неопределено Тогда
Сообщить("Изображение не задано");
Иначе
Данные.Записать("C:\Temp\tovar.jpg");
КонецЕсли;
В запросе реквизит типа «ХранилищеЗначения» можно выбрать, и результат вернёт объект хранилища, у которого затем вызывается Получить(). Однако делать это в цикле по большой выборке — плохая практика: каждая десериализация требует ресурсов, и на тысячах строк обработка заметно замедлится.
Где хранилище значений применяется на практике
Самые распространённые сценарии в типовых и самописных конфигурациях:
- хранение изображений товаров, подписей, логотипов в справочниках;
- прикреплённые файлы к документам (сканы договоров, актов);
- сохранение настроек отчётов и обработок между сеансами — в типовых для этого часто используется системное хранилище
ХранилищеОбщихНастроек, но механизм сериализации тот же; - кэширование результатов тяжёлых вычислений в регистрах сведений;
- передача сложных структур данных между сеансами и фоновыми заданиями.
Отдельный частый случай — параметры фоновых заданий и временные таблицы обмена. Хранилище позволяет передать в фоновое задание объект, который нельзя напрямую сериализовать через параметры, хотя для этих целей чаще используют ПоместитьВоВременноеХранилище — механизм другой, но концептуально похожий.
Куда складывать данные
Подходит для файлов, картинок, настроек, привязанных к конкретному объекту. Ограничение: нельзя искать по содержимому, рост размера базы.
Подходит, если по данным нужен поиск, отборы и отчёты. Ограничение: структура должна быть заранее известна.
Подходит для больших объёмов файлов. Ограничение: нужно обеспечивать доступность каталога и целостность ссылок.
Ограничения и влияние на производительность
Каждое значение в хранилище увеличивает физический размер таблицы базы данных. В файловом варианте это влияет на размер файла 1Cv8.1CD, в клиент-серверном — на размер таблиц в СУБД. Большие BLOB-поля замедляют реструктуризацию, выгрузку в dt и создание резервных копий.
Ещё одно ограничение — невозможность индексирования и поиска. Платформа не умеет строить индексы по содержимому хранилища, поэтому любой отбор возможен только по другим реквизитам объекта. Если бизнес-задача требует искать «все документы, где в прикреплённом файле есть такой-то текст», хранилище значений эту задачу не решит.
Также стоит помнить о версионировании: если в хранилище лежит таблица значений, а в новой версии конфигурации структура её колонок изменилась, старые данные при десериализации могут не соответствовать ожиданиям кода. При изменении формата хранимых структур предусматривайте обработчики обновления.
Как проверить, что всё работает правильно
После записи значения полезно сразу выполнить контрольное чтение: извлечь данные и убедиться, что тип и содержимое соответствуют ожиданиям. Для файлов достаточно проверить размер двоичных данных, для таблиц — количество строк и колонок.
Как проверить результат
Реквизит заполнен, Получить() возвращает объект нужного типа
Получить() возвращает Неопределено или другой тип
Совпадает с размером исходного файла или близок к нему
Нулевой размер или сильное расхождение
Данные доступны и читаются без ошибок
Ошибка десериализации — вероятно, повреждена запись или изменилась структура
Если данные хранятся в регистре сведений, проверку удобно делать через консоль запросов: выбрать запись, убедиться, что поле хранилища не пустое. Для массовой диагностики можно написать обработку, которая проходит по записям, вызывает Получить() и фиксирует ошибки десериализации.
Перед тем как добавлять реквизит типа ХранилищеЗначения в активно используемый объект, оцените средний размер значения и количество записей. Прикиньте итоговый объём: он напрямую попадёт в каждую резервную копию и усложнит перенос базы между серверами.
Частые вопросы о хранилище значений
Можно ли найти объект по содержимому хранилища значений?
Нет. Запросы и отборы не видят внутреннее содержимое хранилища — можно проверить только факт его заполненности. Если поиск по данным необходим, дублируйте ключевые поля в обычные реквизиты или используйте регистры сведений.
Что вернёт метод Получить(), если реквизит пустой?
Метод вернёт Неопределено. Поэтому перед использованием извлечённого значения всегда делайте проверку, иначе обращение к свойствам или методам пустого значения вызовет ошибку выполнения.
Чем хранилище значений отличается от временного хранилища?
Хранилище значений — тип данных для постоянного сохранения в базе. Временное хранилище (ПоместитьВоВременноеХранилище) — механизм передачи данных между клиентом и сервером в рамках сеанса, данные там живут ограниченное время и в базу не пишутся.
Влияет ли сжатие данных на скорость работы?
Да, но умеренно. Сжатие тратит процессорное время при записи и чтении, зато уменьшает объём в базе и ускоряет сетевую передачу. Для текстовых данных и таблиц значений сжатие обычно оправдано, для уже сжатых форматов (JPEG, ZIP) — почти бесполезно.
Можно ли хранить в хранилище ссылку на объект базы?
Технически сериализация ссылок возможна, но делать этого не стоит: при удалении объекта ссылка станет битой, а контроль ссылочной целостности на содержимое хранилища не распространяется. Для связей между объектами используйте обычные реквизиты ссылочного типа.
Как очистить устаревшие данные из хранилищ?
Напишите сервисную обработку: найдите записи по критерию устаревания (например, по дате), установите реквизит в пустое значение или удалите сами записи, затем выполните регламентные операции сжатия таблиц на уровне СУБД, если база клиент-серверная.
Что важно запомнить
Хранилище значений — тип для сохранения в базе произвольных сериализуемых данных: файлов, картинок, таблиц, настроек. Записывается через Новый ХранилищеЗначения(), читается методом Получить(). По содержимому нельзя искать, большие объёмы раздувают базу — для файловых массивов рассматривайте внешнее хранилище.