Разработка и Конфигурация · 11 мин
Хранилище значения в 1С: что это и как с ним работать
Хранилище значения в 1С — что это за тип данных, как сохранить и извлечь файл, картинку или объект, типичные ошибки и практические примеры кода.
Хранилище значения — специальный тип данных в платформе 1С:Предприятие, который позволяет сохранять в базе данных практически любые значения: файлы, картинки, таблицы значений, сериализованные объекты, настройки в формате XML. Без этого типа невозможно было бы хранить, например, фотографии товаров, печатные формы в виде файлов или результаты обмена данными.
Главная особенность хранилища значения — данные внутри него упакованы во внутренний формат платформы и недоступны для прямого чтения запросом. Чтобы получить содержимое, нужно вызвать метод Получить(), а чтобы записать — создать объект ХранилищеЗначения через конструктор Новый ХранилищеЗначения(Значение). Это принципиально отличает его от строк неограниченной длины и других примитивных типов.
Разработчики сталкиваются с хранилищем значения постоянно: реквизиты типа «ХранилищеЗначения» есть в типовых справочниках («Файлы», «Картинки», настройки обменов), регистрах сведений и документах. Понимание того, как устроен этот тип, помогает избежать типичных ошибок — от «пустых» значений в запросах до раздувания базы из-за неправильного хранения больших файлов.
Что такое хранилище значения и зачем оно нужно
Хранилище значения (ValueStorage) — это контейнер, в который платформа упаковывает значение любого поддерживаемого типа с помощью встроенного механизма сериализации. Внутри базы данных такое поле обычно хранится как двоичные данные (BLOB). Платформа сама отвечает за упаковку при записи и распаковку при чтении, поэтому разработчику не нужно вручную преобразовывать объект в байты.
Типичные сценарии использования: хранение двоичных данных файлов и изображений, сохранение таблиц значений и деревьев значений между сеансами, сохранение настроек отчётов и обработок, передача сложных структур данных через параметры длительных операций. В типовых конфигурациях хранилище значения применяется, например, для хранения истории версий файлов и тел писем.
Важно понимать ограничение: хранилище значения не является «магическим» контейнером для всего. В него нельзя поместить ссылки на объекты базы с сохранением их «живого» состояния — при распаковке вы получите сериализованную копию, а не ссылку на актуальный объект. Также не сериализуются некоторые служебные объекты, например открытые формы или соединения.
Как записать значение в хранилище
Запись выполняется в два шага: сначала создаётся объект хранилища с помощью конструктора, затем он присваивается реквизиту объекта и объект записывается. Конструктор принимает значение и необязательный параметр сжатия.
ДвоичныеДанные = Новый ДвоичныеДанные("C:\Files\price.pdf");
НовыйОбъект = Справочники.Файлы.СоздатьЭлемент();
НовыйОбъект.Наименование = "Прайс-лист";
НовыйОбъект.ХранилищеФайла = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
НовыйОбъект.Записать();
Второй параметр конструктора — объект СжатиеДанных со степенью сжатия от 0 (без сжатия) до 9 (максимальное). Для текстовых данных, XML и таблиц значений сжатие обычно даёт заметную экономию места. Для уже сжатых форматов (JPEG, ZIP, PDF с картинками) выигрыш минимален, а время записи увеличивается.
После записи проверьте результат: прочитайте объект заново и вызовите Получить() — должно вернуться исходное значение. Если возвращается Неопределено, скорее всего, реквизит не был заполнен или объект не записан.
Как прочитать и извлечь данные
Чтение выполняется методом Получить(), который возвращает исходное значение в исходном типе. Если хранилище пустое, метод вернёт Неопределено — это нормальная ситуация, которую нужно обрабатывать в коде перед использованием результата.
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ХранилищеФайла ИЗ Справочник.Файлы ГДЕ Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаФайл);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Данные = Выборка.ХранилищеФайла.Получить();
Если Данные <> Неопределено Тогда
Данные.Записать("C:\Temp\price.pdf");
КонецЕсли;
КонецЕсли;
Обратите внимание: в запросе поле типа «ХранилищеЗначения» можно выбрать, но его нельзя использовать в условиях отбора по содержимому, сортировке или группировке. Запрос вернёт сам объект хранилища, а распаковка происходит уже в коде. Сравнивать в запросе можно только факт заполненности — например, проверку на пустое значение через соответствующие конструкции языка запросов.
- 1Получите значение реквизита из объекта или запроса
- 2Вызовите метод Получить() у хранилища
- 3Проверьте результат на Неопределено
- 4Проверьте тип полученного значения через ТипЗнч()
- 5Используйте значение по назначению или сохраните во временный файл
Что можно и нельзя хранить
Хранилище значения поддерживает большинство типов платформы, но у каждого варианта есть свои особенности. Ниже — сопоставление типичных вариантов использования.
| Что храним | Подходит ли | Особенности |
|---|---|---|
| ДвоичныеДанные (файлы) | Да | Стандартный способ хранения файлов в базе; большие файлы раздувают базу |
| Картинка | Да | Используется для изображений товаров, логотипов |
| ТаблицаЗначений, ДеревоЗначений | Да | Удобно для сохранения результатов расчётов и настроек |
| Структура, Соответствие, Массив | Да | Элементы внутри тоже должны быть сериализуемыми |
| Строка неограниченной длины, XML | Да, но избыточно | Для текста часто проще использовать строковый реквизит |
| Ссылки на объекты базы | Технически да, с оговорками | Хранится сериализованное представление; для ссылок используйте обычные ссылочные реквизиты |
| COM-объекты, открытые формы | Нет | Не сериализуются, вызовут ошибку |
Отдельный вопрос — размер. Хранение сотен мегабайт файлов внутри базы увеличивает время резервного копирования, усложняет репликацию и замедляет выборки из таблиц, где поле расположено. В клиент-серверном варианте типовые конфигурации нередко выносят файлы в тома на диске, а в хранилище значения кладут только небольшие данные и служебные структуры.
Хранилище значения в запросах и СКД
В языке запросов поле типа «ХранилищеЗначения» ведёт себя ограниченно: его можно выбрать и передать, но нельзя распаковать средствами запроса. Нет функции, которая вернула бы содержимое прямо в результате запроса. Поэтому типовой шаблон — выбрать поле, обойти выборку и вызвать Получить() в коде.
В СКД ситуация похожая: вывести содержимое хранилища в отчёт напрямую нельзя. Если нужно показать, например, картинку товара, используют вычисляемые поля, обработчики событий компоновки или предварительно подготовленную временную таблицу. Для отбора по факту заполненности хранилища в типовых конфигурациях часто добавляют отдельный булев реквизит-признак, потому что отбор по содержимому хранилища в запросе невозможен.
Производительность и размер базы
Каждое чтение хранилища значения — это загрузка двоичных данных из базы и их десериализация. Если в цикле обрабатываются тысячи элементов справочника с «тяжёлыми» хранилищами, выборка поля хранилища для всех строк сразу может съесть память и время. Оптимизация: выбирайте хранилище только для тех строк, где оно действительно нужно, а для остальных ограничивайтесь лёгкими реквизитами.
Сжатие помогает сократить объём, но добавляет накладные расходы на упаковку и распаковку. Для часто читаемых небольших значений сжатие иногда отключают, для архивных данных — наоборот, ставят максимальное. Проверить реальный вклад конкретной таблицы в размер базы можно штатными средствами СУБД (например, отчётами по размеру таблиц в MS SQL Server) — это безопасная диагностика, не затрагивающая данные.
Если нужно быстро понять, что лежит в хранилище, не запуская отладчик, создайте внешнюю обработку с одной кнопкой: прочитать объект, вызвать Получить(), вывести ТипЗнч(Результат) и, для строкового содержимого, первые символы текста. Это занимает несколько минут и снимает большинство вопросов.
Альтернативы хранилищу значения
Не каждая задача требует именно хранилища. Если нужно хранить длинный текст — подойдёт строковый реквизит неограниченной длины: его можно искать запросом и выводить в отчёты. Если нужно хранить XML-структуру настроек — тоже часто рациональнее строка, потому что XML читаем человеком и легко диагностируется.
Для файлов в типовых конфигурациях предусмотрено хранение в томах на диске, когда в базе остаётся только путь. Для передачи данных между сеансами внутри одного вызова есть параметры сеанса и фоновые задания с собственными механизмами передачи. Хранилище значения оправдано, когда нужно сохранить именно объект платформы (таблицу, картинку, двоичные данные) и восстановить его позже в исходном виде.
Сравнение вариантов хранения
Объекты платформы, файлы, картинки. Минус: не читается запросом, раздувает базу
Тексты, XML, JSON. Плюс: доступна в запросах и отчётах. Минус: только текст
Большие файлы. Плюс: база не растёт. Минус: нужно администрировать доступность томов и бэкапы отдельно
Часто задаваемые вопросы
Как проверить, пустое ли хранилище значения?
В коде вызовите Получить() и сравните результат с Неопределено. В запросе содержимое проверить нельзя — поэтому в прикладных решениях часто заводят отдельный булев реквизит-признак заполненности и обновляют его при записи.
Можно ли вывести содержимое хранилища в отчёт на СКД?
Напрямую — нет, СКД не распаковывает хранилище. Обходные пути: вычисляемые поля с обработчиком, предварительная подготовка временной таблицы с распакованными данными или вывод картинок через механизмы отображения изображений в форме отчёта.
Что вернёт Получить(), если значение не записывалось?
Метод вернёт Неопределено. Это штатная ситуация, а не ошибка, поэтому перед использованием результата всегда делайте проверку, иначе обращение к свойствам или методам результата завершится исключением.
Влияет ли сжатие на скорость работы?
Да, упаковка и распаковка требуют процессорного времени. Для небольших часто читаемых значений сжатие можно отключить, для редко используемых объёмных данных — включить максимальное. Выигрыш по месту зависит от типа данных: текст сжимается хорошо, уже сжатые форматы файлов — почти нет.
Можно ли хранить в хранилище ссылку на элемент справочника?
Технически сериализация возможна, но восстановленное значение не равнозначно «живой» ссылке в контексте текущего соединения. Для связей между объектами используйте обычные ссылочные реквизиты — они поддерживаются запросами, индексами и механизмами целостности.
Как узнать, какие таблицы с хранилищами занимают больше всего места?
В клиент-серверном варианте используйте штатные отчёты СУБД по размеру таблиц и индексов. В файловом варианте оценить вклад отдельных таблиц сложнее — ориентируйтесь на анализ прикладной логики: где хранятся файлы, версии, вложения писем.
Что важно запомнить
Хранилище значения — контейнер для сериализованных данных: файлов, картинок, таблиц и настроек. Записывается через «Новый ХранилищеЗначения(Значение)», читается методом Получить() с обязательной проверкой на Неопределено. В запросах содержимое недоступно, а большие файлы лучше выносить во внешние тома, чтобы не раздувать базу.