Почему таблица, файл или объект не записываются в константу напрямую

· 9 мин

Содержание

В константе 1С нельзя напрямую хранить таблицу значений, структуру, массив, соответствие, список значений, двоичные данные и объекты (СправочникОбъект, ДокументОбъект). Константа принимает только типы, которые можно выбрать в её свойстве «Тип» в конфигураторе: примитивы, ссылки и ХранилищеЗначения. Всё сложное записывают через хранилище значения или переносят в регистр сведений .

Ограничение задаёт платформа, а не конкретная конфигурация. Оно одинаково в Бухгалтерии, ЗУП, УТ и любой самописной базе на 8.3. Обходить запрет можно без потери данных — способов несколько.

Какие типы данных допустимы в константе 1С

Константа — это объект метаданных с одним значением строго заданного типа. Тип выбирают в палитре свойств, в поле «Тип». Что там нет, то в константу не попадёт.

ГруппаЧто можно выбратьКомментарий
ПримитивыСтрока, Число, Дата, БулевоС квалификаторами: длина строки, разрядность числа, состав даты
СсылкиСправочникСсылка.*, ДокументСсылка.*, ПеречислениеСсылка.*, ссылки планов счетов, планов видов характеристик, планов обмена и т.д.Хранится только ссылка, не сам объект
СлужебныеХранилищеЗначения, УникальныйИдентификаторХранилище — единственный путь для сложных значений
Составной типЛюбая комбинация из перечисленногоПустое значение — Неопределено

Чего в списке нет:

  • ❌ ТаблицаЗначений, ДеревоЗначений, СписокЗначений;
  • ❌ Структура, Массив, Соответствие и их фиксированные варианты;
  • ❌ ДвоичныеДанные, Картинка, ТабличныйДокумент;
  • ❌ объекты: СправочникОбъект, ДокументОбъект, менеджеры записей;
  • ❌ тип «Произвольный» — он бывает у переменных и реквизитов формы, но не у реквизитов метаданных.

Причина простая. Каждая константа в базе — это поле таблицы СУБД. Поле должно иметь понятный формат хранения, а коллекции и объекты им не обладают. Поэтому платформа разрешает только то, что раскладывается в колонку, и ХранилищеЗначения — сериализованный «чёрный ящик».

Как узнать тип существующей константы

  1. В конфигураторе откройте ветку «Константы» в дереве конфигурации.
  2. Дважды щёлкните константу и в палитре свойств посмотрите поле «Тип» вместе с квалификаторами.
  3. В режиме предприятия значение можно увидеть через «Все функции» → «Константы». Если пункта «Все функции» нет, включите флажок «Отображать команду “Все функции”» в Главное меню → Сервис → Параметры.

Если тип составной, в поле «Тип» будет перечень через запятую. Именно его и сверяйте с тем, что пишет код: несовпадение типа — главная причина «пропавших» значений.

Константы с типом Булево чаще всего служат основой функциональных опций. Если вы добавляете флаг «Использовать склады», логичнее сделать именно булеву константу, а не хранить флаги в одной строке через разделитель.

Почему таблицу значений нельзя записать в константу

Типичная ситуация: разработчик хочет сохранить настройки обмена — список складов с параметрами. Пишет Константы.НастройкиОбмена.Установить(ТЗ) и получает не то, что ждал.

Ошибки не всегда видно сразу. Если тип константы — строка, платформа приведёт таблицу к типу константы. В базу запишется не таблица, а пустое или бессмысленное значение. Данные пропадут без исключения.

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

  1. В конфигураторе задайте константе тип ХранилищеЗначения.
  2. На сервере упакуйте таблицу в хранилище и запишите.
  3. При чтении распакуйте значение и проверьте его тип.
// Запись (на сервере)
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Склад", Новый ОписаниеТипов("СправочникСсылка.Склады"));
ТЗ.Колонки.Добавить("Префикс", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(5)));

Строка = ТЗ.Добавить();
Строка.Склад = Справочники.Склады.НайтиПоНаименованию("Основной");
Строка.Префикс = "ОС";

Константы.НастройкиОбмена.Установить(Новый ХранилищеЗначения(ТЗ, Новый СжатиеДанных(6)));

// Чтение (на сервере)
Хранилище = Константы.НастройкиОбмена.Получить();
ТЗ = Хранилище.Получить();
Если ТипЗнч(ТЗ) <> Тип("ТаблицаЗначений") Тогда
	ТЗ = Новый ТаблицаЗначений; // константу ещё ни разу не записывали
КонецЕсли;

Тем же способом сохраняют Структуру, Массив, Соответствие, ДеревоЗначений, СписокЗначений и ТабличныйДокумент. В хранилище попадает только то, что платформа умеет сериализовать.

Что не ляжет даже в хранилище

  • ⛔ COMОбъект и внешние соединения — это «живое» подключение, а не данные;
  • ⛔ Запрос, ОписаниеОповещения, формы и элементы форм;
  • ⛔ объекты файловой системы (Файл, открытые потоки чтения и записи).

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

Внутри хранилища структура колонок не контролируется. Переименовали колонку в коде — старое значение прочитается со старым именем. Добавьте в хранилище номер версии формата и обрабатывайте старые версии при чтении.

Ссылки и объекты метаданных в константах

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

Что бывает со ссылкой после удаления элемента

  • 🔗 Удаление через пометку. Константа участвует в контроле ссылочной целостности. Пока она ссылается на элемент, обработка удаления помеченных объектов его не удалит и покажет константу среди мест использования.
  • 💥 Непосредственное удаление. Если элемент удалили в обход контроля (кодом, через Удалить()), константа станет битой ссылкой. В форме вы увидите <Объект не найден> и идентификатор.

Проверка в коде:

ОсновнаяОрганизация = Константы.ОсновнаяОрганизация.Получить();
Если ЗначениеЗаполнено(ОсновнаяОрганизация)
	И ОсновнаяОрганизация.ПолучитьОбъект() = Неопределено Тогда
	// ссылка битая: элемента в базе нет
КонецЕсли;

Ссылки на метаданные

Объект метаданных (например, Метаданные.Документы.РеализацияТоваровУслуг) в константу не записать — такого типа в свойстве «Тип» нет. Сохраняйте полное имя строкой: Метаданные.НайтиПоПолномуИмени("Документ.РеализацияТоваровУслуг") вернёт объект обратно. В конфигурациях на БСП для этого есть справочник идентификаторов объектов метаданных — можно хранить ссылку на его элемент.

Двоичные данные и файлы в константе 1С

ДвоичныеДанные и Картинка не выбираются как тип константы. Логотип, шаблон договора или сертификат кладут в константу с типом ХранилищеЗначения:

// АдресФайла получен на клиенте через помещение файла во временное хранилище
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайла);
Константы.ЛоготипОрганизации.Установить(
	Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9)));

Технически это работает, но есть подводные камни:

  • 🐢 при каждом Получить() платформа читает и распаковывает всё значение целиком — 5 МБ логотипа будут гоняться по сети при каждой печати;
  • 📦 сжатие почти не уменьшает PNG, JPG и PDF — они уже сжаты, а процессорное время тратится;
  • 🔒 константа хранит одну версию: перезаписали — прежний файл потерян, истории нет;
  • 🧾 в форме набора констант поле типа ХранилищеЗначения не редактируется, загрузку и выгрузку придётся писать самим.

Константа годится для одного-двух небольших файлов уровня всей базы. Для десятков файлов, вложений к документам и всего, что растёт, нужен справочник присоединённых файлов (в БСП он уже есть) или хранение на диске с путём в базе.

Пустые значения, Неопределено и приведение типов

Значение, которое не подходит к типу константы, платформа молча приводит к нему. Исключения нет, поэтому такие ошибки находят поздно.

Тип константыЧто записалиЧто окажется в базе
Число(10,2)Неопределено0
Число(10,2)12.34512.35 — округление до 2 знаков
Строка(10)строку из 15 символовпервые 10 символов
Дата (состав «Дата»)дату со временем 14:30дата без времени
СправочникСсылка.СкладыНеопределенопустая ссылка Справочники.Склады.ПустаяСсылка()
Составной типзначение типа, которого нет в составепустое значение, данные не сохранятся

Как отличить «не заполнено» от «ноль»

  • Для одиночного типа пустое значение у каждого своё: 0, "", '00010101', Ложь, пустая ссылка.
  • Для составного типа пустое значение — Неопределено.
  • Универсальная проверка — ЗначениеЗаполнено(). Сравнение с Неопределено для одиночного типа всегда даст Ложь.

Если ноль — допустимое рабочее значение (например, «ставка скидки 0%»), не используйте его как признак «не настроено». Заведите отдельную булеву константу или составной тип, где Неопределено и 0 различаются.

Null в константу не записывается: при записи он превращается в пустое значение типа. Null появится только в запросе при соединении таблиц, а не при чтении самой константы.

Чем заменить константу для сложных данных

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

ЗадачаЧем хранитьПочему не константа
Таблица настроек (склад → параметры)Непериодический регистр сведений с измерениемОтбор, запросы, построчная запись и блокировка
Значение, меняющееся во времени (ставка, курс, ответственный)Периодический регистр сведенийКонстанта не хранит историю: нельзя получить значение на дату
Набор параметров одной записьюРегистр сведений без измерений с несколькими ресурсамиНесколько полей сразу, всё видно в запросе
Настройки конкретного пользователяХранилище общих настроек (ХранилищеОбщихНастроек)Константа одна на всех пользователей
Пароли, токены APIБезопасное хранилище БСПЗначение константы видит любой с правом чтения на неё
Неизменный шаблон, справочная таблицаОбщий макетМеняется вместе с конфигурацией, а не данными
Файлы и вложенияСправочник присоединённых файловНет истории, медленное чтение больших значений

Главный аргумент за регистр сведений — запросы. Поле ХранилищеЗначения можно выбрать в запросе, но нельзя по нему отобрать, сгруппировать или упорядочить. Данные внутри хранилища для запроса невидимы. Регистр с нормальными колонками этого ограничения не имеет.

Где хранить ваши данные?

Ошибки при записи значений в константы

  • 🧵 Запись с клиента. Менеджер Константы доступен на сервере. В управляемой форме чтение и запись выносите в серверную процедуру или используйте реквизит формы НаборКонстант.
  • 🔐 Нет прав. У каждой константы в ролях отдельные права на чтение и изменение. Ошибка нарушения прав при Установить() — повод проверить роль пользователя , а не код.
  • 🔁 Запись в цикле. Каждый вызов Установить() — отдельная транзакция записи и блокировка константы. Запись одной константы тысячу раз в обработке тормозит и конфликтует с другими сеансами. Соберите значение и запишите один раз.
  • 🧩 Разные данные в одном хранилище. Сложили в одну константу-хранилище настройки трёх подсистем — теперь любая правка перезаписывает все три. Одна задача — одна константа.
  • 🗂 Строка-«массив» через разделитель. "Склад1;Склад2;Склад3" в строковой константе ломается от первой точки с запятой в наименовании и не участвует в контроле ссылок. Для списка ссылок нужен регистр сведений.

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

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

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