Разработка и Конфигурация · 11 мин
Хранилище значений 1С: назначение, применение и примеры
Хранилище значений 1С: что это за тип данных, как создать, записать и извлечь значение, примеры кода, типичные ошибки и рекомендации по использованию.
Хранилище значений в 1С — это специальный тип данных, предназначенный для упаковки произвольных значений в единый контейнер с возможностью сериализации, то есть преобразования в поток байтов. С его помощью в поле объекта конфигурации можно сохранить практически любые данные: картинки, файлы, таблицы значений, списки настроек, результаты запросов и даже сложные структуры.
Главная особенность типа «ХранилищеЗначения» в том, что содержимое извлекается из него только целиком. Нельзя обратиться к отдельному элементу массива или строке таблицы, пока значение не извлечено методом Получить(). Это одновременно и ограничение, и преимущество: платформа не тратит ресурсы на разбор содержимого, пока оно не понадобилось.
Тип широко используется в типовых конфигурациях: фотографии товаров в справочнике «Номенклатура», присоединённые файлы, сохранённые настройки отчётов, кэшированные данные обменов — всё это хранится именно в реквизитах с типом «ХранилищеЗначения». Понимание механизма необходимо разработчику при доработке конфигураций и администратору при оценке размера базы.
Как устроен тип «ХранилищеЗначения»
Технически хранилище значений — это обёртка, которая при записи в базу данных преобразует содержимое в двоичный формат. В таблицах СУБД такое поле обычно имеет тип BLOB (binary large object) или его аналог. Платформа 1С сама выполняет сериализацию при помещении значения в хранилище и десериализацию при вызове метода Получить().
Конструктор типа принимает два параметра: само значение и необязательный параметр сжатия — значение системного перечисления СжатиеДанных. По умолчанию применяется сжатие СжатиеДанных.Быстродействие (в ряде версий платформы — без сжатия), поэтому для больших данных имеет смысл явно указывать СжатиеДанных.Сжатие, чтобы уменьшить объём в базе.
Важно понимать, что хранилище значений — это значение, а не ссылка. При присваивании реквизиту объекта создаётся копия данных. Если поместить в хранилище таблицу значений, а затем изменить исходную таблицу, содержимое хранилища не изменится: в момент создания была зафиксирована копия.
Какие данные можно поместить в хранилище
Платформа позволяет сериализовать большинство встроенных типов: примитивы (строки, числа, даты, булево), массивы, структуры, соответствия, таблицы и деревья значений, списки значений, картинки, двоичные данные, табличные документы, результаты запросов, объекты типа «СхемаКомпоновкиДанных» и многие другие.
Есть и ограничения. Нельзя поместить в хранилище ссылки на объекты базы в переносимом виде так, чтобы при обмене они корректно восстановились в другой базе: сериализованная ссылка содержит внутренний идентификатор, который в другой информационной базе укажет на другой объект или ни на что. Также не сериализуются объекты, привязанные к контексту сеанса, — например, элементы форм и некоторые COM-объекты.
Типичное практическое применение:
- изображения и файлы, прикреплённые к элементам справочников;
- настройки пользователей и варианты отчётов;
- кэш результатов тяжёлых вычислений;
- пакеты данных для фоновой обработки и обменов;
- снимки состояния документов для аудита изменений.
Как создать, записать и прочитать хранилище значений
Работа с типом сводится к трём операциям: создание через конструктор, присвоение реквизиту объекта и извлечение методом Получить(). Ниже — типовой пример сохранения картинки в реквизит справочника.
// Запись
Картинка = Новый Картинка("C:\Images\photo.jpg");
ОбъектТовара = ТоварСсылка.ПолучитьОбъект();
ОбъектТовара.Фото = Новый ХранилищеЗначения(Картинка, Новый СжатиеДанных(9));
ОбъектТовара.Записать();
// Чтение
Запрос = Новый Запрос("ВЫБРАТЬ Фото ИЗ Справочник.Номенклатура ГДЕ Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", ТоварСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
КартинкаИзБазы = Выборка.Фото.Получить();
КонецЕсли;Обратите внимание на чтение: если реквизит не заполнен, метод Получить() вернёт Неопределено. Перед использованием результата всегда проверяйте его на Неопределено, иначе обращение к методам или свойствам полученного значения вызовет ошибку выполнения.
В запросах хранилище значений можно выбирать как обычное поле, но нельзя сравнивать содержимое, искать по нему или использовать в условиях по смыслу — доступна только проверка на заполненность через конструкции вида НЕ Хранилище ЕСТЬ NULL в сочетании с соединениями, либо проверка после выборки.
- 1Прочитайте файл в ДвоичныеДанные или Картинку
- 2Создайте хранилище: Новый ХранилищеЗначения(Данные, Сжатие)
- 3Присвойте хранилище реквизиту объекта и вызовите Записать()
- 4Для проверки прочитайте реквизит и вызовите Получить()
- 5Сравните размер или контрольную сумму результата с исходным файлом
Где применяется в конфигурации и как добавить реквизит
Чтобы использовать хранилище в собственной разработке, добавьте объекту метаданных (справочнику, документу, регистру сведений) реквизит с типом «ХранилищеЗначения». В дереве конфигурации это делается через палитру свойств реквизита: выберите тип, снимите лишние флажки составного типа, оставив только «ХранилищеЗначения».
Для регистров сведений хранилище часто используют как ресурс: измерение — ссылка на объект, ресурс — хранилище с данными. Такая схема применяется, например, для хранения нескольких изображений одного товара или версий присоединённых файлов, когда одного реквизита справочника недостаточно.
При проектировании учитывайте, что данные из хранилища нельзя индексировать и включать в полнотекстовый поиск как структурированные значения. Если по содержимому потребуется отбор или поиск, выносите ключевые атрибуты в отдельные примитивные реквизиты, а в хранилище помещайте только «тяжёлую» часть.
Хранилище значений или отдельные реквизиты
Подходит для файлов, картинок, таблиц, настроек. Ограничение: нельзя искать и отбирать по содержимому, данные извлекаются только целиком.
Подходят для значений, по которым нужны отборы, сортировка, индексы и связи. Ограничение: не позволяют хранить файлы и сложные структуры.
Подходят для файлов в типовых конфигурациях: готовые механизмы хранения, версий и подписей. Ограничение: требуют подсистемы БСП.
Производительность, размер базы и типичные риски
Главная цена использования хранилища — рост объёма базы и нагрузка при чтении. Каждое обращение к реквизиту с последующим Получить() означает чтение BLOB-поля и десериализацию всего содержимого. Если в запросе выбрать хранилище для тысячи строк, платформа вычитает тысячу двоичных объектов — это заметно медленнее, чем выборка примитивных полей.
Практические рекомендации по снижению нагрузки:
- выбирайте поле с хранилищем в запросе только тогда, когда оно действительно нужно;
- явно указывайте сжатие для больших данных — это уменьшает объём на диске;
- не храните в хранилище то, что можно вычислить заново за приемлемое время;
- для больших файлов рассмотрите тома хранения файлов (в типовых) вместо размещения в базе.
Ещё один риск — обмены и распределённые базы. Хранилище сериализует ссылки по внутренним идентификаторам, поэтому перенос сериализованных структур со ссылками между разными базами может привести к «битым» ссылкам после десериализации. Для обменов используйте механизмы конвертации данных, а не прямую передачу хранилищ.
Как проверить содержимое и отладить проблемы
Отладка хранилища неудобна тем, что в табло и в форме содержимое не отображается — видна только надпись «Хранилище значений». Чтобы увидеть, что внутри, извлеките значение методом Получить() и выведите его тип через ТипЗнч(), а затем исследуйте само значение.
Признаки типичных проблем: Получить() возвращает Неопределено (реквизит пуст или значение не записано), ошибка десериализации при чтении (данные повреждены или записаны внешним инструментом в обход платформы), неожиданный тип результата (в реквизит писали разные типы в разных обработчиках).
Как проверить результат
Возвращается значение ожидаемого типа
Неопределено или ошибка десериализации
Совпадает с типом, который помещали при записи
Другой тип — значит, реквизит перезаписывали из другого места
Рост соответствует объёму загруженных данных с учётом сжатия
Рост в разы больше объёма файлов — сжатие не применяется
Типичные ошибки при работе с хранилищем
Большинство проблем с хранилищем значений связано не с самим типом, а с неверными ожиданиями от его поведения. Разбор частых ошибок помогает избежать потери данных и лишней нагрузки.
Отдельно стоит предупредить о попытках редактировать содержимое BLOB-полей напрямую средствами СУБД. Платформа хранит данные в собственном формате сериализации, и любое внешнее вмешательство почти гарантированно приведёт к ошибкам десериализации или повреждению данных.
Частые вопросы о хранилище значений 1С
Чем хранилище значений отличается от реквизита типа «Строка неограниченной длины»?
Неограниченная строка хранит только текст и позволяет выполнять поиск по подстроке. Хранилище значений принимает любые сериализуемые типы — картинки, таблицы, файлы, — но не поддерживает поиск по содержимому и извлекается только целиком.
Можно ли найти записи по содержимому хранилища значений?
Напрямую — нет: запрос не может заглянуть внутрь сериализованных данных. Если нужен отбор, продублируйте ключевые параметры в отдельные примитивные реквизиты при записи и стройте поиск по ним.
Что возвращает метод Получить(), если реквизит не заполнен?
Значение Неопределено. Поэтому перед обращением к свойствам и методам результата всегда выполняйте проверку, иначе получите ошибку выполнения в момент обращения.
Нужно ли указывать сжатие при создании хранилища?
Для небольших структур сжатие почти не влияет на результат. Для файлов и больших таблиц явное указание сжатия заметно уменьшает объём в базе за счёт небольшого роста времени записи и чтения.
Можно ли хранить в хранилище ссылки на объекты базы?
Технически ссылки сериализуются, но переносить такое хранилище между разными базами нельзя: внутренние идентификаторы не совпадут, и после десериализации ссылки станут недействительными. Внутри одной базы это допустимо.
Как узнать, что именно лежит в хранилище конкретной записи?
Прочитайте реквизит запросом или через объект, вызовите Получить() и определите тип результата функцией ТипЗнч(). Далее исследуйте значение штатными средствами отладчика.
Что важно запомнить
Хранилище значений — контейнер для сериализации любых данных в одном реквизите. Создаётся конструктором с возможным сжатием, читается только целиком методом Получить(). Подходит для файлов, картинок и настроек, но не для данных, по которым нужен поиск. Контролируйте размер базы, проверяйте результат на Неопределено и не переносите сериализованные ссылки между базами.