Перечисления во встроенном языке 1С 8.3: код модуля, запросы, имена и индексы значений

· 9 мин

Содержание

В модуле на сервере к перечислению обращаются так: Перечисления.ИмяПеречисления.ИмяЗначения, например Перечисления.СтатусыЗаказов.Выполнен. В клиентском коде принято писать ПредопределенноеЗначение("Перечисление.СтатусыЗаказов.Выполнен"), а в тексте запроса — ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Выполнен). Разница в одной букве: в коде модуля пишут «Перечисления» во множественном числе, в запросе и в строке для ПредопределенноеЗначение — «Перечисление» в единственном.

Это правило платформы 1С:Предприятие 8.3, оно одинаково для любой конфигурации: БП 3.0, ЗУП 3.1, УТ 11 или самописной. Имена перечислений и значений в примерах условные: точное имя в вашей базе смотрите в конфигураторе, в дереве метаданных, ветка «Перечисления».

Перечисление в 1С: что хранится в базе и чем оно отличается от справочника

Перечисление — объект конфигурации с фиксированным списком значений. Список задаёт разработчик в конфигураторе, пользователь в режиме «Предприятие» не может добавить, удалить или переименовать значение.

У каждого значения есть:

  • 🔤 Имя — идентификатор для кода (Выполнен, НДС20). Латиница и кириллица допустимы, пробелы нет.
  • 🏷️ Синоним — то, что видит пользователь в поле формы («Выполнен», «20%»).
  • 🔢 Порядок — позиция в списке. От неё зависит сортировка в запросах и индекс значения.

В реквизите документа или справочника хранится не текст, а ссылка на значение — тип ПеречислениеСсылка.ИмяПеречисления. Пустое значение — это Перечисления.ИмяПеречисления.ПустаяСсылка(), а не Неопределено.

Где перечисления встречаются постоянно: ставки НДС, виды операций документов, статусы заказов, юридическое или физическое лицо в карточке контрагента, периодичность. Везде, где список короткий и меняется только вместе с кодом.

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

Пять способов обратиться к значению перечисления в коде

Способ 1. Через менеджер перечислений

Самый прямой вариант для серверного кода, модулей объектов и менеджеров:

Если Заказ.Статус = Перечисления.СтатусыЗаказов.Выполнен Тогда
    // заказ закрыт, отгрузку не создаём
    Возврат;
КонецЕсли;

Объект.ВидОперации = Перечисления.ВидыОперацийРеализация.Товары;

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

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

Способ 2. Через ПредопределенноеЗначение

Функция глобального контекста. Принимает строку с полным именем значения и работает одинаково на клиенте и сервере:

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

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

Пустая ссылка через эту функцию: ПредопределенноеЗначение("Перечисление.СтатусыЗаказов.ПустаяСсылка").

Способ 3. Параметром запроса

Значение передают в запрос так же, как любую ссылку:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Заказ.Ссылка
|ИЗ
|    Документ.ЗаказКлиента КАК Заказ
|ГДЕ
|    Заказ.Статус = &Статус";
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыЗаказов.Выполнен);

Подходит, когда значение вычисляется в коде или приходит извне.

Способ 4. Функцией ЗНАЧЕНИЕ в тексте запроса

Когда значение известно заранее, его пишут прямо в текст. Подробно — в следующем разделе.

Способ 5. По имени из строки

Менеджер перечисления индексируется строкой с именем значения:

ИмяЗначения = "Выполнен";
Статус = Перечисления.СтатусыЗаказов[ИмяЗначения];

Так же индексируется и коллекция Перечисления — по имени самого перечисления. Это основа динамического доступа, о нём ниже.

СпособГде работаетКогда выбирать
Перечисления.Имя.ЗначениеСервер, модули объектовОбычный серверный код
ПредопределенноеЗначение("Перечисление.…")Клиент и серверМодули форм, общие модули с клиентом
Параметр &СтатусЗапросЗначение вычисляется в коде
ЗНАЧЕНИЕ(Перечисление.…)Текст запроса, СКДЗначение известно заранее
Перечисления.Имя[Строка]СерверИмя значения хранится в строке

Как обращаться к перечислению в запросе 1С

ЗНАЧЕНИЕ() в условии

ВЫБРАТЬ
    Реализация.Ссылка,
    Реализация.СуммаДокумента
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРеализация.Товары)

Внутри скобок — только литерал. Параметр вида ЗНАЧЕНИЕ(&Вид) или выражение запрос не примет. Если значение меняется, используйте параметр.

Несколько значений перечисляют через В:

ГДЕ
    Заказ.Статус В (ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.КОбеспечению),
                    ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.КОтгрузке))

Проверка на незаполненность:

ГДЕ
    Заказ.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка)

Системные перечисления в запросе пишутся так же, без слова «Перечисление»: ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход).

Выборка всех значений из таблицы перечисления

У каждого перечисления есть таблица в языке запросов с полями Ссылка и Порядок:

ВЫБРАТЬ
    Статусы.Ссылка КАК Статус,
    ПРЕДСТАВЛЕНИЕ(Статусы.Ссылка) КАК Наименование
ИЗ
    Перечисление.СтатусыЗаказов КАК Статусы
УПОРЯДОЧИТЬ ПО
    Статусы.Порядок

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

Сортировка и представление

При УПОРЯДОЧИТЬ ПО Заказ.Статус записи сортируются по порядку значений в конфигураторе, а не по алфавиту синонимов. Нужна алфавитная сортировка — сортируйте по ПРЕДСТАВЛЕНИЕ(Заказ.Статус).

В системе компоновки данных (СКД) запрос с ЗНАЧЕНИЕ() работает без изменений. В отборах отчёта значение выбирают из списка, писать код не нужно.

Получение значения перечисления по строке, имени и индексу

Динамический доступ нужен, когда имя перечисления или значения приходит из настроек, файла загрузки, HTTP-запроса или формируется в универсальной процедуре.

Значение по имени перечисления и имени значения

ИмяПеречисления = "СтатусыЗаказов";
ИмяЗначения = "Выполнен";

Статус = Перечисления[ИмяПеречисления][ИмяЗначения];

// то же самое через строку, работает и на клиенте
Статус = ПредопределенноеЗначение("Перечисление." + ИмяПеречисления + "." + ИмяЗначения);

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

МетаПеречисление = Метаданные.Перечисления.Найти(ИмяПеречисления);
Если МетаПеречисление = Неопределено Тогда
    ВызватьИсключение "Нет перечисления " + ИмяПеречисления;
КонецЕсли;
Если МетаПеречисление.ЗначенияПеречисления.Найти(ИмяЗначения) = Неопределено Тогда
    ВызватьИсключение "Нет значения " + ИмяЗначения;
КонецЕсли;

Имя значения по ссылке

Обратная задача: есть ссылка, нужно её имя для кода (не синоним). Строка Строка(Статус) вернёт синоним, а он может быть переведён или переименован. Надёжный путь — через индекс и метаданные:

&НаСервереБезКонтекста
Функция ИмяЗначенияПеречисления(Значение)
    МетаПеречисление = Значение.Метаданные();
    Индекс = Перечисления[МетаПеречисление.Имя].Индекс(Значение);
    Возврат МетаПеречисление.ЗначенияПеречисления[Индекс].Имя;
КонецФункции

В конфигурациях на БСП для этого есть готовая функция ОбщегоНазначения.ИмяЗначенияПеречисления(Значение), лучше взять её.

Значение по индексу

Метод Получить(Индекс) менеджера возвращает значение по позиции, отсчёт с нуля:

ПервыйСтатус = Перечисления.СтатусыЗаказов.Получить(0);

Индекс меняется, если разработчик переставит значения в конфигураторе. Не храните индексы в базе и файлах, храните имена.

Список значений для формы

Типовая задача — заполнить список выбора поля только частью значений и с собственными подписями:

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

Проверка типа значения: ТипЗнч(Значение) = Тип("ПеречислениеСсылка.СтатусыЗаказов"). Описание типа для реквизита формы или колонки таблицы: Новый ОписаниеТипов("ПеречислениеСсылка.СтатусыЗаказов").

Ошибки при обращении к перечислению и их причины

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

Ещё несколько ловушек, которые не дают явной ошибки:

  • 🌐 Сравнение по синониму. Строка(Статус) = "Выполнен" сломается, как только синоним поправят или база запустится на другом языке интерфейса.
  • 📋 Составной тип. Если реквизит допускает несколько типов, пустое значение — Неопределено. Здесь как раз помогает ЗначениеЗаполнено(), которая проверяет оба случая.
  • 🔀 Логика на порядке. Условие Индекс(Статус) > 2 «все статусы после отгрузки» тихо сломается при добавлении нового значения в середину списка. Перечисляйте нужные значения явно.

Расширения, обмены и производительность при работе с перечислениями

Перечисления в расширении конфигурации

Чтобы использовать перечисление основной конфигурации в коде расширения, его не обязательно заимствовать: обращение Перечисления.СтатусыЗаказов.Выполнен работает из модулей расширения как есть.

Заимствовать перечисление нужно, если вы добавляете в него собственные значения. Актуальные версии платформы 8.3 это позволяют. Добавленные значения существуют, пока подключено расширение. Если расширение отключить, реквизиты, где они записаны, получат битые ссылки.

Имена своих значений начинайте с префикса расширения, например мр_ОжидаетСогласования. Так при обновлении типовой не возникнет конфликта, если разработчики конфигурации добавят значение с тем же именем.

Перечисления в обменах данными

При выгрузке в XML через СериализаторXDTO и в правилах обмена значения перечислений передаются по имени. Отсюда два следствия:

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

Если обмен самописный, держите таблицу соответствия имён и не передавайте синонимы — они меняются чаще.

Производительность

Обращение Перечисления.Имя.Значение не выполняет запрос к базе. Сравнение значений перечисления — сравнение ссылок, оно быстрое и в коде, и в условии ГДЕ.

Медленным код становится в двух местах:

  • ⏱️ Разыменование в цикле. Заказ.Статус у ссылки на документ читает документ из базы. Получите статусы одним запросом, а не по одному в цикле.
  • 🔍 Отбор без индекса. Условие по реквизиту-перечислению в большой таблице без индекса читает её целиком. Для частых отборов включите индексирование реквизита в конфигураторе.

Когда вместо перечисления лучше взять справочник

Перечисление хорошо там, где список значений привязан к алгоритмам. Код ветвится по каждому значению, и новое значение всё равно потребует доработки.

Если список меняется по бизнес-причинам, выбирайте другой объект:

ЗадачаЧто использоватьПочему
Пользователь сам добавляет значенияСправочникПеречисление правит только разработчик в конфигураторе
Нужны реквизиты у значения (ставка, счёт, срок)Справочник с предопределёнными элементамиУ значения перечисления реквизитов нет
Часть значений фиксирована, часть добавляют пользователиСправочник с предопределёнными элементамиК предопределённым обращаются из кода, остальные свободные
Набор свойств разного типаПлан видов характеристикЗначения хранят свой тип
Список нужен только внутри одного алгоритмаКонстанта в коде, ФиксированнаяСтруктураНе нужен объект метаданных и таблица в базе

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

Частые вопросы про обращение к перечислениям

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