Чтение констант в 1С 8.3 на сервере, клиенте и в запросе

· 9 мин

Содержание

Получить значение константы в 1С проще всего одной строкой на сервере: Константы.ИмяКонстанты.Получить(). Частая ошибка — вызвать эту же строку в модуле формы на клиенте. В тонком клиенте и веб-клиенте менеджер Константы недоступен, поэтому значение нужно читать в серверной процедуре и возвращать на клиент.

Дальше — все рабочие способы для 1С:Предприятия 8.3: прямое чтение, менеджер значения, набор констант, запрос, функциональные опции и кэш. Плюс права доступа и ошибки, которые встречаются при чтении констант чаще всего.

Как устроены константы и какие типы данных в них лежат

Константа — объект метаданных, который хранит одно значение на всю информационную базу. Не на пользователя и не на организацию, а одно на всех. Типичные примеры: основная валюта учёта, флаг «Использовать несколько складов», адрес сервиса, дата запрета изменения в простых конфигурациях.

В базе данных каждая константа хранится в отдельной таблице с одной строкой. Отсюда два следствия:

  • 📌 каждое чтение константы — это обращение к СУБД;
  • 📌 запись одной константы не блокирует остальные.

Тип значения задаётся в конфигураторе, в свойствах константы. Варианты:

ТипПримерЧто вернёт Получить()
Примитивный (Строка, Число, Дата, Булево)ИспользоватьВалютныйУчетсамо значение
Ссылка на объектОсновнаяОрганизацияссылку, например СправочникСсылка.Организации
Составной типнесколько типов ссылокзначение одного из типов или Неопределено
ХранилищеЗначениянастройки, файл, картинкаобъект ХранилищеЗначения, а не данные внутри

Если константа ещё ни разу не записывалась, Получить() вернёт пустое значение её типа: пустую строку, 0, пустую дату, Ложь или пустую ссылку. Для составного типа — Неопределено.

Как посмотреть значение константы без кода

Перед отладкой полезно убедиться, что в константе вообще что-то записано. В режиме 1С:Предприятие откройте Главное меню → Функции для технического специалиста (если пункта нет, включите его в Сервис → Параметры, флажок «Режим технического специалиста»). В дереве найдите ветку «Константы» и откройте нужную: форма покажет текущее значение.

Так за минуту выясняется, где проблема: в коде или в данных. Пустое значение в форме — значит, константу просто не заполнили, и код здесь ни при чём.

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

Получение значения константы на сервере

Весь код этого раздела выполняется на сервере, в толстом клиенте и во внешнем соединении. Для тонкого клиента — следующий раздел.

Способ 1. Метод Получить()

Базовый вариант, когда нужна одна константа:

Валюта = Константы.ВалютаРегламентированногоУчета.Получить();

Имя константы — это её имя в дереве метаданных, а не синоним. Синоним «Валюта регламентированного учета» в коде не работает .

Если имя константы приходит строкой (например, из настройки), используйте обращение по индексу:

ИмяКонстанты = "ВалютаРегламентированногоУчета";
Если Метаданные.Константы.Найти(ИмяКонстанты) <> Неопределено Тогда
    Значение = Константы[ИмяКонстанты].Получить();
КонецЕсли;

Проверка через Метаданные.Константы.Найти() защищает от ошибки времени выполнения, если константу переименовали или удалили.

Способ 2. Менеджер значения константы

Менеджер значения — это объект, через который константу читают и записывают как обычный объект: с событиями ПередЗаписью и ПриЗаписи в модуле менеджера значения.

МенеджерЗначения = Константы.ОсновнаяОрганизация.СоздатьМенеджерЗначения();
МенеджерЗначения.Прочитать();
Организация = МенеджерЗначения.Значение;

Для простого чтения он избыточен. Нужен, когда вы читаете значение, чтобы потом изменить его и записать с проверками и обработчиками.

Способ 3. Набор констант

Если нужно сразу несколько констант, удобен набор:

Набор = Константы.СоздатьНабор("ИспользоватьВалютныйУчет, ВалютаРегламентированногоУчета");
Набор.Прочитать();

Если Набор.ИспользоватьВалютныйУчет Тогда
    Валюта = Набор.ВалютаРегламентированногоУчета;
КонецЕсли;

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

Значение из хранилища

Для константы типа ХранилищеЗначения нужен второй вызов Получить() — уже у самого хранилища:

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

Проверка на Неопределено обязательна: пустое хранилище вернёт именно его.

Какой способ выбрать

ЗадачаСпособКомментарий
Прочитать одно значениеПолучить()самый короткий код
Прочитать и записать с проверкамименеджер значениясрабатывают обработчики модуля
Прочитать 3–10 константнабор константодин объект вместо нескольких вызовов
Нужна константа внутри выборки данныхзапроссм. раздел про запросы

Как получить значение константы на клиенте

В модуле управляемой формы с директивой &НаКлиенте такая строка не скомпилируется в тонком клиенте:

&НаКлиенте
Процедура Команда1(Команда)
    Валюта = Константы.ВалютаРегламентированногоУчета.Получить(); // ошибка в тонком клиенте
КонецПроцедуры

Правильная схема — серверная функция без контекста формы, которая возвращает значение:

&НаКлиенте
Процедура Команда1(Команда)
    Валюта = ВалютаУчетаНаСервере();
КонецПроцедуры

&НаСервереБезКонтекста
Функция ВалютаУчетаНаСервере()
    Возврат Константы.ВалютаРегламентированногоУчета.Получить();
КонецФункции

Директива &НаСервереБезКонтекста важна: при &НаСервере на сервер уходят все данные формы, а здесь они не нужны. Разница заметна на тяжёлых формах документов с табличными частями.

Если константу читают из многих мест, вынесите функцию в общий модуль с флажками Сервер и Вызов сервера:

// Общий модуль НастройкиВызовСервера (Сервер, Вызов сервера)
Функция ЗначениеКонстанты(ИмяКонстанты) Экспорт
    Если Метаданные.Константы.Найти(ИмяКонстанты) = Неопределено Тогда
        Возврат Неопределено;
    КонецЕсли;
    Возврат Константы[ИмяКонстанты].Получить();
КонецФункции

Не открывайте такой универсальный метод на клиент без проверки прав: любой пользователь сможет прочитать через него любую константу, включая служебные. Безопаснее отдельная функция на каждую нужную настройку или белый список имён.

Несколько констант за один серверный вызов

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

&НаСервереБезКонтекста
Функция НастройкиДляФормы()
    Набор = Константы.СоздатьНабор("ИспользоватьВалютныйУчет, ВалютаРегламентированногоУчета, ОсновнаяОрганизация");
    Набор.Прочитать();

    Результат = Новый Структура;
    Результат.Вставить("ИспользоватьВалюту", Набор.ИспользоватьВалютныйУчет);
    Результат.Вставить("Валюта", Набор.ВалютаРегламентированногоУчета);
    Результат.Вставить("Организация", Набор.ОсновнаяОрганизация);
    Возврат Результат;
КонецФункции

На клиенте: Настройки = НастройкиДляФормы(); Валюта = Настройки.Валюта;. Ссылки на справочники передаются на клиент без проблем, а вот объекты (СправочникОбъект) — нет, их на клиент не возвращают.

Булевы константы и функциональные опции

Если булева константа служит хранилищем функциональной опции, её значение можно получить прямо на клиенте, без своего серверного вызова:

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    Если ПолучитьФункциональнуюОпцию("ИспользоватьВалютныйУчет") Тогда
        // показать валютные поля
    КонецЕсли;
КонецПроцедуры

Аргумент — имя функциональной опции, а не константы. Они могут совпадать, но это разные объекты метаданных. Значения опций платформа кэширует, поэтому вызов дешёвый.

Значение на форме при открытии

Если значение нужно сразу при открытии формы, прочитайте его в ПриСозданииНаСервере и положите в реквизит формы. Тогда на клиенте оно уже есть, и лишних серверных вызовов не будет:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    ИспользоватьВалюту = Константы.ИспользоватьВалютныйУчет.Получить();
КонецПроцедуры

Значение константы в запросе

Константы доступны в языке запросов двумя путями.

Таблица «Константы» — одна строка, каждая константа в ней колонка:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Константы.ВалютаРегламентированногоУчета КАК Валюта,
|    Константы.ОсновнаяОрганизация КАК Организация
|ИЗ
|    Константы КАК Константы";

Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
    Валюта = Выборка.Валюта;
    Организация = Выборка.Организация;
КонецЕсли;

Таблица отдельной константы — поле Значение:

Запрос = Новый Запрос(
"ВЫБРАТЬ
|    Значение
|ИЗ
|    Константа.ВалютаРегламентированногоУчета");

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

"ВЫБРАТЬ
|    Товары.Ссылка,
|    Товары.Цена
|ИЗ
|    Справочник.Номенклатура КАК Товары
|        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Константы КАК Константы
|        ПО Товары.ВалютаЦены = Константы.ВалютаРегламентированногоУчета"

Будьте внимательны с незаполненной константой. Если в ней пустая ссылка, внутреннее соединение по ней не найдёт ни одной строки, и запрос молча вернёт пустой результат. Ошибки не будет, отчёт просто окажется пустым. Когда пустое значение допустимо, проверяйте константу до выполнения запроса и сообщайте пользователю, что настройка не заполнена, вместо пустого списка.

Можно и через параметр: прочитать константу заранее и передать Запрос.УстановитьПараметр("Валюта", Валюта). Это читается проще, а по скорости разница на практике мала.

Поля типа ХранилищеЗначения в запросе можно выбрать, но нельзя использовать в условиях, соединениях и упорядочивании.

Оптимизация и кэширование значений констант

Одно чтение константы — быстрая операция. Проблемы начинаются, когда её читают в цикле:

// Плохо: 10 000 обращений к базе
Для Каждого Строка Из Товары Цикл
    Если Строка.Валюта = Константы.ВалютаРегламентированногоУчета.Получить() Тогда
        // ...
    КонецЕсли;
КонецЦикла;

// Хорошо: одно обращение
ВалютаУчета = Константы.ВалютаРегламентированногоУчета.Получить();
Для Каждого Строка Из Товары Цикл
    Если Строка.Валюта = ВалютаУчета Тогда
        // ...
    КонецЕсли;
КонецЦикла;

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

// Общий модуль НастройкиПовтИсп (Сервер, Вызов сервера, На время сеанса)
Функция ВалютаУчета() Экспорт
    Возврат Константы.ВалютаРегламентированногоУчета.Получить();
КонецФункции

Вызов НастройкиПовтИсп.ВалютаУчета() обратится к базе один раз, дальше значение берётся из кэша.

РежимСколько живёт кэшКогда подходит
Без кэша—значение меняется часто
На время вызовадо конца серверного вызовазначение нужно много раз в одной операции
На время сеансавесь сеанс пользователянастройка меняется раз в месяц или реже

Минус кэша на сеанс: после изменения константы другие пользователи увидят старое значение. Сбросить кэш в текущем сеансе можно методом ОбновитьПовторноИспользуемыеЗначения(). В чужих сеансах он сам не сбросится — пользователям придётся перезапустить программу. Поэтому для настроек, которые меняют на ходу, хватит кэша «на время вызова».

Повторно используемый модуль отдаёт всем вызывающим один и тот же экземпляр значения. Если функция возвращает структуру или массив, их нельзя менять в вызывающем коде — иначе вы испортите кэш. Возвращайте ФиксированнаяСтруктура и ФиксированныйМассив.

Права доступа и ошибки при чтении констант

У константы в роли есть права Чтение и Изменение, а также интерактивные Просмотр и Редактирование. Если у пользователя нет права Чтение, вызов Получить() завершится ошибкой Нарушение прав доступа!.

Когда служебную константу нужно прочитать для пользователя без прав, используют привилегированный режим на сервере:

УстановитьПривилегированныйРежим(Истина);
Адрес = Константы.АдресСервисаОбмена.Получить();
УстановитьПривилегированныйРежим(Ложь);

Альтернатива — общий модуль с флажком Привилегированный. В обоих случаях верните на клиент только то, что пользователю действительно нужно. Пароли и токены в константах лучше не хранить вовсе: для них в платформе есть безопасное хранилище данных, а в БСП — модуль ОбщегоНазначения с функциями чтения из него.

Типичные ошибки при получении значения константы:

Диагностика: выберите симптом

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

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