Какие типы данных поддерживает хранилище значений в 1С

· 9 мин

Содержание

В хранилище значений можно положить почти любое сериализуемое значение платформы: число, строку, дату, булево, таблицу значений, дерево значений, список значений, табличный документ, картинку и двоичные данные файла. Это универсальный «контейнер», в который упаковывают данные, у которых нет собственного поля подходящего типа в структуре объекта.

Тип называется ХранилищеЗначения. Реквизит такого типа заводят в конфигураторе у справочника, документа, регистра сведений или константы, а значение кладут и достают кодом: Новый ХранилищеЗначения(Значение) на запись и .Получить() на чтение. Ниже — какие именно типы туда помещаются, как настроить реквизит со сжатием, что хранить нельзя и почему от этого поля тяжелеет база.

Что реально помещается в контейнер

Правило простое: в хранилище значений ложится всё, что платформа умеет сериализовать во внутреннее представление. Это большинство прикладных и примитивных типов.

Чаще всего туда кладут:

  • 📄 Двоичные данные (ДвоичныеДанные) — содержимое любого файла: PDF, архив, .epf, скан.
  • 🖼 Картинку (Картинка) — логотип, фото номенклатуры, аватар.
  • 📊 Табличный документ (ТабличныйДокумент) — готовый макет или сформированный отчёт.
  • 🗂 Таблицу значений и дерево значений — результат расчёта, снимок данных формы.
  • 📋 Список значений, структуру, соответствие, массив — сериализуемые коллекции.
  • 🔢 Примитивы — число, строку, дату, булево, UUID.

Помещаются и ссылки на объекты (СправочникСсылка, ДокументСсылка), но тут есть ловушка — о ней отдельный раздел ниже.

Запись и чтение в самом простом виде:

// Запись значения в реквизит
Объект.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);

// Чтение обратно
ДвоичныеДанные = Объект.ДанныеФайла.Получить();

Метод Получить() возвращает исходное значение того же типа, что было записано. Если реквизит пустой или данные не удалось восстановить, вернётся Неопределено — всегда проверяйте результат на Неопределено перед использованием.

Как сохранить файл, картинку и табличный документ

Самый частый сценарий — хранение файла. Файл сначала читают в ДвоичныеДанные, потом упаковывают:

ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
Объект.Вложение = Новый ХранилищеЗначения(ДвоичныеДанные);

Картинку из файла готовят через Новый Картинка(...) или сразу хранят как ДвоичныеДанные и собирают картинку при показе. Для вывода в поле формы картинку достают так:

ДанныеКартинки = Объект.Логотип.Получить();

Табличный документ упаковывается целиком, вместе с настройками печати и группировками:

Хранилище = Новый ХранилищеЗначения(ТабДокумент);

Для картинок и документов, которые вы не меняете, а только показываете, сжатие почти не даёт выигрыша: форматы PNG, JPG, PDF, DOCX уже сжаты внутри. А вот табличный документ, таблица значений и текст сжимаются хорошо.

Чтобы отдать сохранённый файл пользователю на скачивание, данные достают из хранилища и помещают во временное хранилище сеанса, а дальше вызывают механизм получения файла:

ДвоичныеДанные = Объект.Вложение.Получить();
Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
// затем на клиенте — ПолучитьФайл(Адрес, ИмяФайла)

Имя и расширение файла в самом хранилище не лежат — их держат в отдельном реквизите рядом. Это важно: по одним двоичным данным платформа не знает, PDF это или картинка.

Двоичные данные против ссылки на картинку

Если картинка используется в одном месте — храните двоичные данные прямо в реквизите. Если одна и та же картинка нужна многим объектам — заведите отдельный справочник с хранилищем и ссылайтесь на его элемент, чтобы не дублировать байты в каждой записи.

Как создать реквизит типа ХранилищеЗначения

Реквизит заводят в конфигураторе. Порядок действий:

  1. Откройте дерево конфигурации и найдите объект — например, нужный справочник или документ.
  2. Разверните ветку Реквизиты, через контекстное меню добавьте новый реквизит.
  3. В палитре свойств найдите свойство Тип и нажмите кнопку выбора.
  4. В списке типов отметьте ХранилищеЗначения. Это единственный тип для этого реквизита — составным его делать смысла нет.
  5. Задайте имя и синоним, сохраните и обновите конфигурацию базы данных (F7, затем принять изменения структуры).

На форме такой реквизит по умолчанию не показывается читаемым элементом — платформе нечего отрисовать «из коробки». Обычно рядом с ним на форме размещают кнопку «Загрузить файл» и поле картинки, а сам реквизит заполняют и читают кодом.

Проверка перед вводом реквизита в эксплуатацию
Выполнено: 0 / 5

Сжатие данных: второй параметр конструктора

У конструктора ХранилищеЗначения есть второй, необязательный параметр — объект СжатиеДанных с уровнем от 0 до 9.

// Максимальное сжатие
Хранилище = Новый ХранилищеЗначения(ТабДокумент, Новый СжатиеДанных(9));

// Без сжатия (эквивалент отсутствия второго параметра)
Хранилище = Новый ХранилищеЗначения(ТабДокумент, Новый СжатиеДанных(0));

Чем выше уровень, тем компактнее результат и тем дольше упаковка. Для фоновой записи редких больших объектов берите 9, для частой записи — компромиссные 5–6 или вовсе 0.

УровеньКогда применятьЧто получаете
0Уже сжатые файлы (PDF, PNG, ZIP)Экономим процессор, место не выигрываем
5–6Частая запись, средние объёмыБаланс скорости и размера
9Редкая запись крупных данныхМинимальный размер, выше нагрузка на процессор

Если второй параметр не указать, значение сохранится без сжатия. Для таблиц значений и текстовых данных это заметно раздувает поле — задавайте сжатие осознанно.

Что нельзя положить в хранилище и почему

Не всё в платформе сериализуется, поэтому часть значений в контейнер не попадёт:

  • ❌ Управляемую форму и её элементы управления.
  • ❌ COM-объекты и объекты внешнего соединения.
  • ❌ Открытые соединения (HTTP, TCP), файловые потоки, живые курсоры.
  • ❌ Любой объект, который существует только во время сеанса и не имеет внутреннего представления.

Попытка записать такое значение приведёт к ошибке в момент создания ХранилищеЗначения.

Отдельный, не очевидный случай — ссылки на объекты. Записать СправочникСсылка в хранилище платформа позволит, но это будет снимок ссылки, а не настоящая связь. Последствия:

  • ссылочная целостность не действует — объект, на который «ссылается» хранилище, спокойно удалится, и контроль ссылок этого не заметит;
  • по такому полю нельзя построить соединение в запросе;
  • если данные переносят в другую базу, ссылка внутри хранилища не перемапится.

Поэтому для настоящих связей заводите реквизит ссылочного типа, а хранилище используйте только для данных, у которых нет своего поля.

Ещё один нюанс — версии. Значение, записанное в новой версии платформы, старая прочитать не всегда сумеет: при даунгрейде Получить() может вернуть Неопределено. Если база живёт на разных версиях платформы (например, при постепенном обновлении серверов), держите это в голове и не завязывайте критичную логику на содержимое хранилища без проверки результата.

Хранилище значений в запросах и в списках

Это ключевое ограничение, из-за которого новички попадают впросак. Поле типа ХранилищеЗначения в языке запросов можно только выбрать в список выборки — и всё.

По нему нельзя:

  • задать условие в ГДЕ;
  • построить СОЕДИНЕНИЕ;
  • группировать (СГРУППИРОВАТЬ ПО);
  • упорядочивать (УПОРЯДОЧИТЬ ПО).

Платформа не умеет заглядывать внутрь упакованного значения, поэтому фильтровать и искать по содержимому нечем. Если по данным нужен поиск или отбор — выносите их в обычные реквизиты (или в отдельный регистр сведений ), а в хранилище кладите только то, что программа читает целиком и сразу.

В динамических списках и отчётах такое поле тоже не выводится как колонка — показывать там нечего. На форме его разворачивают в картинку или достают для скачивания файла.

Как это поле влияет на производительность базы

Хранилище хранится как большой двоичный фрагмент (BLOB) внутри таблицы объекта. Отсюда практические последствия:

  • 📦 Таблица пухнет. Десять тысяч документов по 2 МБ вложения — это 20 ГБ в одной таблице. Растёт и объём резервной копии, и время её создания.
  • 🐢 Чтение объекта целиком тянет и хранилище. Когда вы читаете Объект = Ссылка.ПолучитьОбъект(), в память поднимается и содержимое хранилища, даже если оно вам сейчас не нужно.
  • 🔁 Реструктуризация замедляется. Любое изменение структуры объекта с «тяжёлым» реквизитом — долгая операция под монопольным доступом.

Что с этим делать:

  1. Не кладите крупные файлы в часто читаемые и часто проводимые объекты.
  2. Для присоединённых файлов используйте штатный механизм библиотеки стандартных подсистем с хранением в томах на диске, а не в поле базы — так база не раздувается.
  3. Если хранилище всё же нужно в объекте — держите его в отдельном подчинённом объекте (например, в регистре сведений «данные по ссылке»), чтобы основная таблица оставалась лёгкой.
  4. Применяйте сжатие для сжимаемых данных.

Правило опытного разработчика: хранилище значений — для данных, которые читают изредка и целиком. Для всего, что участвует в отборах, отчётах и соединениях, нужны обычные типизированные реквизиты.

Хранилище, тома или отдельный справочник — что выбрать

Когда встаёт вопрос «где держать бинарные данные», у разработчика три рабочих варианта. Выбор зависит от размера данных и от того, как часто читается сам объект.

СпособКогда подходитМинусы
Реквизит-хранилище в объектеНебольшие редкие данные (настройка, снимок, печать)Пухнет таблица и резервная копия
Тома хранения файлов (БСП)Файлы любого размера, много вложенийНужна настройка каталогов и прав на диске
Отдельный справочник/регистр с хранилищемДанные нужны не всегда, объект читается частоЛишний объект метаданных, дополнительный запрос

Чем крупнее и чаще данные — тем сильнее перевес в сторону томов. Реквизит прямо в часто проводимом документе оставляйте только для совсем небольших значений.

Где хранилище значений применяют на практике

Типовые конфигурации и платформа используют этот тип постоянно:

  • 🧩 Дополнительные отчёты и обработки. Файл .epf/.erf хранится в реквизите-хранилище соответствующего справочника.
  • 📎 Присоединённые файлы и их версии. Содержимое и предыдущие версии файла упаковываются в хранилище (если не вынесены в тома).
  • ⚙️ Пользовательские настройки и настройки компоновки данных — сохранённый вариант отчёта.
  • 🏷 Картинки номенклатуры, логотипы, печати и подписи для печатных форм.
  • 💾 Кэш и снимки. Результат тяжёлого расчёта, который дорого считать заново, иногда кэшируют в хранилище с меткой актуальности.

Проверьте, что усвоили главное:

Проверьте себя
По какому полю типа ХранилищеЗначения можно задать условие в запросе?
Что вернёт метод Получить() у пустого реквизита-хранилища?
Что по сути попадёт в базу, если записать в хранилище ссылку на элемент справочника?

Частые вопросы

Можно ли одно хранилище значений вложить в другое?
Технически да — вложенная структура сериализуется. Но смысла в этом нет: распаковка идёт в два шага, а выигрыша никакого. Лучше хранить данные плоско.
Чем `ХранилищеЗначения` отличается от типа `ДвоичныеДанные`?
ДвоичныеДанные — это просто байты, их кладут в хранилище как одно из возможных значений. ХранилищеЗначения — обёртка-контейнер, которая умеет сериализовать и примитивы, и коллекции, и табличный документ, и сжимать результат.
Почему после записи файла размер базы вырос больше, чем сам файл?
Если не задать сжатие, служебная обёртка добавляет к данным накладные расходы на сериализацию. Для сжимаемых данных укажите Новый СжатиеДанных(9) — часто поле становится в разы меньше.
Как достать из хранилища таблицу значений, если не помню исходный тип?
Просто вызовите .Получить() — вернётся значение того типа, что был записан. Тип можно проверить функцией ТипЗнч(). Если данные записывал другой разработчик и тип неизвестен, узнать его можно только из кода записи.
Что будет, если реквизит-хранилище участвует в обмене данными?
Содержимое перенесётся как есть. Но если внутри лежала ссылка на объект, в приёмнике она не перемапится на новые идентификаторы — это ещё один довод не хранить ссылки внутри хранилища.