Какие типы данных поддерживает хранилище значений в 1С
Содержание
В хранилище значений можно положить почти любое сериализуемое значение платформы: число, строку, дату, булево, таблицу значений, дерево значений, список значений, табличный документ, картинку и двоичные данные файла. Это универсальный «контейнер», в который упаковывают данные, у которых нет собственного поля подходящего типа в структуре объекта.
Тип называется ХранилищеЗначения. Реквизит такого типа заводят в конфигураторе у справочника, документа, регистра сведений или константы, а значение кладут и достают кодом: Новый ХранилищеЗначения(Значение) на запись и .Получить() на чтение. Ниже — какие именно типы туда помещаются, как настроить реквизит со сжатием, что хранить нельзя и почему от этого поля тяжелеет база.
Что реально помещается в контейнер
Правило простое: в хранилище значений ложится всё, что платформа умеет сериализовать во внутреннее представление. Это большинство прикладных и примитивных типов.
Чаще всего туда кладут:
- 📄 Двоичные данные (
ДвоичныеДанные) — содержимое любого файла: PDF, архив, .epf, скан. - 🖼 Картинку (
Картинка) — логотип, фото номенклатуры, аватар. - 📊 Табличный документ (
ТабличныйДокумент) — готовый макет или сформированный отчёт. - 🗂 Таблицу значений и дерево значений — результат расчёта, снимок данных формы.
- 📋 Список значений, структуру, соответствие, массив — сериализуемые коллекции.
- 🔢 Примитивы — число, строку, дату, булево, UUID.
Помещаются и ссылки на объекты (СправочникСсылка, ДокументСсылка), но тут есть ловушка — о ней отдельный раздел ниже.
Запись и чтение в самом простом виде:
// Запись значения в реквизит
Объект.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
// Чтение обратно
ДвоичныеДанные = Объект.ДанныеФайла.Получить();
Метод Получить() возвращает исходное значение того же типа, что было записано. Если реквизит пустой или данные не удалось восстановить, вернётся Неопределено — всегда проверяйте результат на Неопределено перед использованием.
Как сохранить файл, картинку и табличный документ
Самый частый сценарий — хранение файла. Файл сначала читают в ДвоичныеДанные, потом упаковывают:
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
Объект.Вложение = Новый ХранилищеЗначения(ДвоичныеДанные);
Картинку из файла готовят через Новый Картинка(...) или сразу хранят как ДвоичныеДанные и собирают картинку при показе. Для вывода в поле формы картинку достают так:
ДанныеКартинки = Объект.Логотип.Получить();
Табличный документ упаковывается целиком, вместе с настройками печати и группировками:
Хранилище = Новый ХранилищеЗначения(ТабДокумент);
Для картинок и документов, которые вы не меняете, а только показываете, сжатие почти не даёт выигрыша: форматы PNG, JPG, PDF, DOCX уже сжаты внутри. А вот табличный документ, таблица значений и текст сжимаются хорошо.
Чтобы отдать сохранённый файл пользователю на скачивание, данные достают из хранилища и помещают во временное хранилище сеанса, а дальше вызывают механизм получения файла:
ДвоичныеДанные = Объект.Вложение.Получить();
Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
// затем на клиенте — ПолучитьФайл(Адрес, ИмяФайла)
Имя и расширение файла в самом хранилище не лежат — их держат в отдельном реквизите рядом. Это важно: по одним двоичным данным платформа не знает, PDF это или картинка.
Двоичные данные против ссылки на картинку
Если картинка используется в одном месте — храните двоичные данные прямо в реквизите. Если одна и та же картинка нужна многим объектам — заведите отдельный справочник с хранилищем и ссылайтесь на его элемент, чтобы не дублировать байты в каждой записи.
Как создать реквизит типа ХранилищеЗначения
Реквизит заводят в конфигураторе. Порядок действий:
- Откройте дерево конфигурации и найдите объект — например, нужный справочник или документ.
- Разверните ветку
Реквизиты, через контекстное меню добавьте новый реквизит. - В палитре свойств найдите свойство
Типи нажмите кнопку выбора. - В списке типов отметьте
ХранилищеЗначения. Это единственный тип для этого реквизита — составным его делать смысла нет. - Задайте имя и синоним, сохраните и обновите конфигурацию базы данных (
F7, затем принять изменения структуры).
На форме такой реквизит по умолчанию не показывается читаемым элементом — платформе нечего отрисовать «из коробки». Обычно рядом с ним на форме размещают кнопку «Загрузить файл» и поле картинки, а сам реквизит заполняют и читают кодом.
Сжатие данных: второй параметр конструктора
У конструктора ХранилищеЗначения есть второй, необязательный параметр — объект СжатиеДанных с уровнем от 0 до 9.
// Максимальное сжатие
Хранилище = Новый ХранилищеЗначения(ТабДокумент, Новый СжатиеДанных(9));
// Без сжатия (эквивалент отсутствия второго параметра)
Хранилище = Новый ХранилищеЗначения(ТабДокумент, Новый СжатиеДанных(0));
Чем выше уровень, тем компактнее результат и тем дольше упаковка. Для фоновой записи редких больших объектов берите 9, для частой записи — компромиссные 5–6 или вовсе 0.
| Уровень | Когда применять | Что получаете |
|---|---|---|
| 0 | Уже сжатые файлы (PDF, PNG, ZIP) | Экономим процессор, место не выигрываем |
| 5–6 | Частая запись, средние объёмы | Баланс скорости и размера |
| 9 | Редкая запись крупных данных | Минимальный размер, выше нагрузка на процессор |
Если второй параметр не указать, значение сохранится без сжатия. Для таблиц значений и текстовых данных это заметно раздувает поле — задавайте сжатие осознанно.
Что нельзя положить в хранилище и почему
Не всё в платформе сериализуется, поэтому часть значений в контейнер не попадёт:
- ❌ Управляемую форму и её элементы управления.
- ❌ COM-объекты и объекты внешнего соединения.
- ❌ Открытые соединения (HTTP, TCP), файловые потоки, живые курсоры.
- ❌ Любой объект, который существует только во время сеанса и не имеет внутреннего представления.
Попытка записать такое значение приведёт к ошибке в момент создания ХранилищеЗначения.
Отдельный, не очевидный случай — ссылки на объекты. Записать СправочникСсылка в хранилище платформа позволит, но это будет снимок ссылки, а не настоящая связь. Последствия:
- ссылочная целостность не действует — объект, на который «ссылается» хранилище, спокойно удалится, и контроль ссылок этого не заметит;
- по такому полю нельзя построить соединение в запросе;
- если данные переносят в другую базу, ссылка внутри хранилища не перемапится.
Поэтому для настоящих связей заводите реквизит ссылочного типа, а хранилище используйте только для данных, у которых нет своего поля.
Ещё один нюанс — версии. Значение, записанное в новой версии платформы, старая прочитать не всегда сумеет: при даунгрейде Получить() может вернуть Неопределено. Если база живёт на разных версиях платформы (например, при постепенном обновлении серверов), держите это в голове и не завязывайте критичную логику на содержимое хранилища без проверки результата.
Хранилище значений в запросах и в списках
Это ключевое ограничение, из-за которого новички попадают впросак. Поле типа ХранилищеЗначения в языке запросов можно только выбрать в список выборки — и всё.
По нему нельзя:
- задать условие в
ГДЕ; - построить
СОЕДИНЕНИЕ; - группировать (
СГРУППИРОВАТЬ ПО); - упорядочивать (
УПОРЯДОЧИТЬ ПО).
Платформа не умеет заглядывать внутрь упакованного значения, поэтому фильтровать и искать по содержимому нечем. Если по данным нужен поиск или отбор — выносите их в обычные реквизиты (или в отдельный регистр сведений ), а в хранилище кладите только то, что программа читает целиком и сразу.
В динамических списках и отчётах такое поле тоже не выводится как колонка — показывать там нечего. На форме его разворачивают в картинку или достают для скачивания файла.
Как это поле влияет на производительность базы
Хранилище хранится как большой двоичный фрагмент (BLOB) внутри таблицы объекта. Отсюда практические последствия:
- 📦 Таблица пухнет. Десять тысяч документов по 2 МБ вложения — это 20 ГБ в одной таблице. Растёт и объём резервной копии, и время её создания.
- 🐢 Чтение объекта целиком тянет и хранилище. Когда вы читаете
Объект = Ссылка.ПолучитьОбъект(), в память поднимается и содержимое хранилища, даже если оно вам сейчас не нужно. - 🔁 Реструктуризация замедляется. Любое изменение структуры объекта с «тяжёлым» реквизитом — долгая операция под монопольным доступом.
Что с этим делать:
- Не кладите крупные файлы в часто читаемые и часто проводимые объекты.
- Для присоединённых файлов используйте штатный механизм библиотеки стандартных подсистем с хранением в томах на диске, а не в поле базы — так база не раздувается.
- Если хранилище всё же нужно в объекте — держите его в отдельном подчинённом объекте (например, в регистре сведений «данные по ссылке»), чтобы основная таблица оставалась лёгкой.
- Применяйте сжатие для сжимаемых данных.
Правило опытного разработчика: хранилище значений — для данных, которые читают изредка и целиком. Для всего, что участвует в отборах, отчётах и соединениях, нужны обычные типизированные реквизиты.
Хранилище, тома или отдельный справочник — что выбрать
Когда встаёт вопрос «где держать бинарные данные», у разработчика три рабочих варианта. Выбор зависит от размера данных и от того, как часто читается сам объект.
| Способ | Когда подходит | Минусы |
|---|---|---|
| Реквизит-хранилище в объекте | Небольшие редкие данные (настройка, снимок, печать) | Пухнет таблица и резервная копия |
| Тома хранения файлов (БСП) | Файлы любого размера, много вложений | Нужна настройка каталогов и прав на диске |
| Отдельный справочник/регистр с хранилищем | Данные нужны не всегда, объект читается часто | Лишний объект метаданных, дополнительный запрос |
Чем крупнее и чаще данные — тем сильнее перевес в сторону томов. Реквизит прямо в часто проводимом документе оставляйте только для совсем небольших значений.
Где хранилище значений применяют на практике
Типовые конфигурации и платформа используют этот тип постоянно:
- 🧩 Дополнительные отчёты и обработки. Файл
.epf/.erfхранится в реквизите-хранилище соответствующего справочника. - 📎 Присоединённые файлы и их версии. Содержимое и предыдущие версии файла упаковываются в хранилище (если не вынесены в тома).
- ⚙️ Пользовательские настройки и настройки компоновки данных — сохранённый вариант отчёта.
- 🏷 Картинки номенклатуры, логотипы, печати и подписи для печатных форм.
- 💾 Кэш и снимки. Результат тяжёлого расчёта, который дорого считать заново, иногда кэшируют в хранилище с меткой актуальности.
Проверьте, что усвоили главное:
Частые вопросы
Можно ли одно хранилище значений вложить в другое?
Чем `ХранилищеЗначения` отличается от типа `ДвоичныеДанные`?
ДвоичныеДанные — это просто байты, их кладут в хранилище как одно из возможных значений. ХранилищеЗначения — обёртка-контейнер, которая умеет сериализовать и примитивы, и коллекции, и табличный документ, и сжимать результат.Почему после записи файла размер базы вырос больше, чем сам файл?
Новый СжатиеДанных(9) — часто поле становится в разы меньше.Как достать из хранилища таблицу значений, если не помню исходный тип?
.Получить() — вернётся значение того типа, что был записан. Тип можно проверить функцией ТипЗнч(). Если данные записывал другой разработчик и тип неизвестен, узнать его можно только из кода записи.