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