Почему таблица, файл или объект не записываются в константу напрямую
Содержание
В константе 1С нельзя напрямую хранить таблицу значений, структуру, массив, соответствие, список значений, двоичные данные и объекты (СправочникОбъект, ДокументОбъект). Константа принимает только типы, которые можно выбрать в её свойстве «Тип» в конфигураторе: примитивы, ссылки и ХранилищеЗначения. Всё сложное записывают через хранилище значения или переносят в регистр сведений
.
Ограничение задаёт платформа, а не конкретная конфигурация. Оно одинаково в Бухгалтерии, ЗУП, УТ и любой самописной базе на 8.3. Обходить запрет можно без потери данных — способов несколько.
Какие типы данных допустимы в константе 1С
Константа — это объект метаданных с одним значением строго заданного типа. Тип выбирают в палитре свойств, в поле «Тип». Что там нет, то в константу не попадёт.
| Группа | Что можно выбрать | Комментарий |
|---|---|---|
| Примитивы | Строка, Число, Дата, Булево | С квалификаторами: длина строки, разрядность числа, состав даты |
| Ссылки | СправочникСсылка.*, ДокументСсылка.*, ПеречислениеСсылка.*, ссылки планов счетов, планов видов характеристик, планов обмена и т.д. | Хранится только ссылка, не сам объект |
| Служебные | ХранилищеЗначения, УникальныйИдентификатор | Хранилище — единственный путь для сложных значений |
| Составной тип | Любая комбинация из перечисленного | Пустое значение — Неопределено |
Чего в списке нет:
- ❌
ТаблицаЗначений,ДеревоЗначений,СписокЗначений; - ❌
Структура,Массив,Соответствиеи их фиксированные варианты; - ❌
ДвоичныеДанные,Картинка,ТабличныйДокумент; - ❌ объекты:
СправочникОбъект,ДокументОбъект, менеджеры записей; - ❌ тип «Произвольный» — он бывает у переменных и реквизитов формы, но не у реквизитов метаданных.
Причина простая. Каждая константа в базе — это поле таблицы СУБД. Поле должно иметь понятный формат хранения, а коллекции и объекты им не обладают. Поэтому платформа разрешает только то, что раскладывается в колонку, и ХранилищеЗначения — сериализованный «чёрный ящик».
Как узнать тип существующей константы
- В конфигураторе откройте ветку «Константы» в дереве конфигурации.
- Дважды щёлкните константу и в палитре свойств посмотрите поле «Тип» вместе с квалификаторами.
- В режиме предприятия значение можно увидеть через «Все функции» → «Константы». Если пункта «Все функции» нет, включите флажок «Отображать команду “Все функции”» в
Главное меню → Сервис → Параметры.
Если тип составной, в поле «Тип» будет перечень через запятую. Именно его и сверяйте с тем, что пишет код: несовпадение типа — главная причина «пропавших» значений.
Константы с типом Булево чаще всего служат основой функциональных опций. Если вы добавляете флаг «Использовать склады», логичнее сделать именно булеву константу, а не хранить флаги в одной строке через разделитель.
Почему таблицу значений нельзя записать в константу
Типичная ситуация: разработчик хочет сохранить настройки обмена — список складов с параметрами. Пишет Константы.НастройкиОбмена.Установить(ТЗ) и получает не то, что ждал.
Ошибки не всегда видно сразу. Если тип константы — строка, платформа приведёт таблицу к типу константы. В базу запишется не таблица, а пустое или бессмысленное значение. Данные пропадут без исключения.
Как правильно: через ХранилищеЗначения
- В конфигураторе задайте константе тип
ХранилищеЗначения. - На сервере упакуйте таблицу в хранилище и запишите.
- При чтении распакуйте значение и проверьте его тип.
// Запись (на сервере)
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Склад", Новый ОписаниеТипов("СправочникСсылка.Склады"));
ТЗ.Колонки.Добавить("Префикс", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(5)));
Строка = ТЗ.Добавить();
Строка.Склад = Справочники.Склады.НайтиПоНаименованию("Основной");
Строка.Префикс = "ОС";
Константы.НастройкиОбмена.Установить(Новый ХранилищеЗначения(ТЗ, Новый СжатиеДанных(6)));
// Чтение (на сервере)
Хранилище = Константы.НастройкиОбмена.Получить();
ТЗ = Хранилище.Получить();
Если ТипЗнч(ТЗ) <> Тип("ТаблицаЗначений") Тогда
ТЗ = Новый ТаблицаЗначений; // константу ещё ни разу не записывали
КонецЕсли;
Тем же способом сохраняют Структуру, Массив, Соответствие, ДеревоЗначений, СписокЗначений и ТабличныйДокумент. В хранилище попадает только то, что платформа умеет сериализовать.
Что не ляжет даже в хранилище
- ⛔
COMОбъекти внешние соединения — это «живое» подключение, а не данные; - ⛔
Запрос,ОписаниеОповещения, формы и элементы форм; - ⛔ объекты файловой системы (
Файл, открытые потоки чтения и записи).
При попытке упаковать такое значение конструктор ХранилищеЗначения вызовет исключение. Сохраняйте не объект, а исходные параметры: текст запроса, путь к файлу, строку подключения.
Внутри хранилища структура колонок не контролируется. Переименовали колонку в коде — старое значение прочитается со старым именем. Добавьте в хранилище номер версии формата и обрабатывайте старые версии при чтении.
Ссылки и объекты метаданных в константах
Константа с типом СправочникСсылка.Организации хранит ссылку — по сути, уникальный идентификатор элемента. Сам элемент со всеми реквизитами в константу не копируется. Поэтому СправочникОбъект в константе хранить бессмысленно: храните ссылку и получайте объект через ПолучитьОбъект().
Что бывает со ссылкой после удаления элемента
- 🔗 Удаление через пометку. Константа участвует в контроле ссылочной целостности. Пока она ссылается на элемент, обработка удаления помеченных объектов его не удалит и покажет константу среди мест использования.
- 💥 Непосредственное удаление. Если элемент удалили в обход контроля (кодом, через
Удалить()), константа станет битой ссылкой. В форме вы увидите<Объект не найден>и идентификатор.
Проверка в коде:
ОсновнаяОрганизация = Константы.ОсновнаяОрганизация.Получить();
Если ЗначениеЗаполнено(ОсновнаяОрганизация)
И ОсновнаяОрганизация.ПолучитьОбъект() = Неопределено Тогда
// ссылка битая: элемента в базе нет
КонецЕсли;
Ссылки на метаданные
Объект метаданных (например, Метаданные.Документы.РеализацияТоваровУслуг) в константу не записать — такого типа в свойстве «Тип» нет. Сохраняйте полное имя строкой: Метаданные.НайтиПоПолномуИмени("Документ.РеализацияТоваровУслуг") вернёт объект обратно. В конфигурациях на БСП для этого есть справочник идентификаторов объектов метаданных — можно хранить ссылку на его элемент.
Двоичные данные и файлы в константе 1С
ДвоичныеДанные и Картинка не выбираются как тип константы. Логотип, шаблон договора или сертификат кладут в константу с типом ХранилищеЗначения:
// АдресФайла получен на клиенте через помещение файла во временное хранилище
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайла);
Константы.ЛоготипОрганизации.Установить(
Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9)));
Технически это работает, но есть подводные камни:
- 🐢 при каждом
Получить()платформа читает и распаковывает всё значение целиком — 5 МБ логотипа будут гоняться по сети при каждой печати; - 📦 сжатие почти не уменьшает PNG, JPG и PDF — они уже сжаты, а процессорное время тратится;
- 🔒 константа хранит одну версию: перезаписали — прежний файл потерян, истории нет;
- 🧾 в форме набора констант поле типа
ХранилищеЗначенияне редактируется, загрузку и выгрузку придётся писать самим.
Константа годится для одного-двух небольших файлов уровня всей базы. Для десятков файлов, вложений к документам и всего, что растёт, нужен справочник присоединённых файлов (в БСП он уже есть) или хранение на диске с путём в базе.
Пустые значения, Неопределено и приведение типов
Значение, которое не подходит к типу константы, платформа молча приводит к нему. Исключения нет, поэтому такие ошибки находят поздно.
| Тип константы | Что записали | Что окажется в базе |
|---|---|---|
Число(10,2) | Неопределено | 0 |
Число(10,2) | 12.345 | 12.35 — округление до 2 знаков |
Строка(10) | строку из 15 символов | первые 10 символов |
Дата (состав «Дата») | дату со временем 14:30 | дата без времени |
СправочникСсылка.Склады | Неопределено | пустая ссылка Справочники.Склады.ПустаяСсылка() |
| Составной тип | значение типа, которого нет в составе | пустое значение, данные не сохранятся |
Как отличить «не заполнено» от «ноль»
- Для одиночного типа пустое значение у каждого своё:
0,"",'00010101',Ложь, пустая ссылка. - Для составного типа пустое значение —
Неопределено. - Универсальная проверка —
ЗначениеЗаполнено(). Сравнение сНеопределенодля одиночного типа всегда дастЛожь.
Если ноль — допустимое рабочее значение (например, «ставка скидки 0%»), не используйте его как признак «не настроено». Заведите отдельную булеву константу или составной тип, где Неопределено и 0 различаются.
Null в константу не записывается: при записи он превращается в пустое значение типа. Null появится только в запросе при соединении таблиц, а не при чтении самой константы.
Чем заменить константу для сложных данных
Константа хороша для одного значения на всю базу без истории. Если хоть одно из этих условий не выполняется, берите другой объект.
| Задача | Чем хранить | Почему не константа |
|---|---|---|
| Таблица настроек (склад → параметры) | Непериодический регистр сведений с измерением | Отбор, запросы, построчная запись и блокировка |
| Значение, меняющееся во времени (ставка, курс, ответственный) | Периодический регистр сведений | Константа не хранит историю: нельзя получить значение на дату |
| Набор параметров одной записью | Регистр сведений без измерений с несколькими ресурсами | Несколько полей сразу, всё видно в запросе |
| Настройки конкретного пользователя | Хранилище общих настроек (ХранилищеОбщихНастроек) | Константа одна на всех пользователей |
| Пароли, токены API | Безопасное хранилище БСП | Значение константы видит любой с правом чтения на неё |
| Неизменный шаблон, справочная таблица | Общий макет | Меняется вместе с конфигурацией, а не данными |
| Файлы и вложения | Справочник присоединённых файлов | Нет истории, медленное чтение больших значений |
Главный аргумент за регистр сведений — запросы. Поле ХранилищеЗначения можно выбрать в запросе, но нельзя по нему отобрать, сгруппировать или упорядочить. Данные внутри хранилища для запроса невидимы. Регистр с нормальными колонками этого ограничения не имеет.
Ошибки при записи значений в константы
- 🧵 Запись с клиента. Менеджер
Константыдоступен на сервере. В управляемой форме чтение и запись выносите в серверную процедуру или используйте реквизит формыНаборКонстант. - 🔐 Нет прав. У каждой константы в ролях отдельные права на чтение и изменение. Ошибка нарушения прав при
Установить()— повод проверить роль пользователя , а не код. - 🔁 Запись в цикле. Каждый вызов
Установить()— отдельная транзакция записи и блокировка константы. Запись одной константы тысячу раз в обработке тормозит и конфликтует с другими сеансами. Соберите значение и запишите один раз. - 🧩 Разные данные в одном хранилище. Сложили в одну константу-хранилище настройки трёх подсистем — теперь любая правка перезаписывает все три. Одна задача — одна константа.
- 🗂 Строка-«массив» через разделитель.
"Склад1;Склад2;Склад3"в строковой константе ломается от первой точки с запятой в наименовании и не участвует в контроле ссылок. Для списка ссылок нужен регистр сведений.
Меняете тип у константы, в которой уже есть данные? При обновлении конфигурации базы данных платформа попытается конвертировать старое значение в новый тип. При несовместимых типах значение будет потеряно. Перед такой правкой сохраните текущее значение отдельно.
Частые вопросы
Можно ли хранить в константе ссылку на любой справочник?
СправочникСсылка или составной тип из нужных справочников. Пустое значение у составного типа — Неопределено.Видна ли константа типа ХранилищеЗначения в запросе?
Константы, но содержимое для запроса закрыто: ни отбора, ни сортировки по нему. Распаковывают значение только кодом через Получить().Есть ли ограничение длины строковой константы?
ПОДСТРОКА, а большие тексты лучше хранить в хранилище значения или в макете.Почему значение константы в форме пустое, хотя код его записал?
ТипЗнч().