Перечисления во встроенном языке 1С 8.3: код модуля, запросы, имена и индексы значений
Содержание
В модуле на сервере к перечислению обращаются так: Перечисления.ИмяПеречисления.ИмяЗначения, например Перечисления.СтатусыЗаказов.Выполнен. В клиентском коде принято писать ПредопределенноеЗначение("Перечисление.СтатусыЗаказов.Выполнен"), а в тексте запроса — ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Выполнен). Разница в одной букве: в коде модуля пишут «Перечисления» во множественном числе, в запросе и в строке для ПредопределенноеЗначение — «Перечисление» в единственном.
Это правило платформы 1С:Предприятие 8.3, оно одинаково для любой конфигурации: БП 3.0, ЗУП 3.1, УТ 11 или самописной. Имена перечислений и значений в примерах условные: точное имя в вашей базе смотрите в конфигураторе, в дереве метаданных, ветка «Перечисления».
Перечисление в 1С: что хранится в базе и чем оно отличается от справочника
Перечисление — объект конфигурации с фиксированным списком значений. Список задаёт разработчик в конфигураторе, пользователь в режиме «Предприятие» не может добавить, удалить или переименовать значение.
У каждого значения есть:
- 🔤 Имя — идентификатор для кода (
Выполнен,НДС20). Латиница и кириллица допустимы, пробелы нет. - 🏷️ Синоним — то, что видит пользователь в поле формы («Выполнен», «20%»).
- 🔢 Порядок — позиция в списке. От неё зависит сортировка в запросах и индекс значения.
В реквизите документа или справочника хранится не текст, а ссылка на значение — тип ПеречислениеСсылка.ИмяПеречисления. Пустое значение — это Перечисления.ИмяПеречисления.ПустаяСсылка(), а не Неопределено.
Где перечисления встречаются постоянно: ставки НДС, виды операций документов, статусы заказов, юридическое или физическое лицо в карточке контрагента, периодичность. Везде, где список короткий и меняется только вместе с кодом.
Кроме перечислений конфигурации, есть системные перечисления платформы: ВидДвиженияНакопления, ВидСчета, РежимЗаписиДокумента, ГоризонтальноеПоложение и другие. К ним обращаются без слова «Перечисления»: ВидДвиженияНакопления.Приход, РежимЗаписиДокумента.Проведение.
Пять способов обратиться к значению перечисления в коде
Способ 1. Через менеджер перечислений
Самый прямой вариант для серверного кода, модулей объектов и менеджеров:
Если Заказ.Статус = Перечисления.СтатусыЗаказов.Выполнен Тогда
// заказ закрыт, отгрузку не создаём
Возврат;
КонецЕсли;
Объект.ВидОперации = Перечисления.ВидыОперацийРеализация.Товары;
Контекстная подсказка в конфигураторе показывает имена значений после точки, так что опечатку легко заметить ещё при наборе. Если она всё же проскочила, ошибка всплывёт при выполнении строки.
Тот же синтаксис работает в модуле менеджера самого перечисления. Там удобно держать функции вроде «список статусов, после которых заказ нельзя менять», чтобы не повторять один и тот же набор значений в разных модулях.
Способ 2. Через ПредопределенноеЗначение
Функция глобального контекста. Принимает строку с полным именем значения и работает одинаково на клиенте и сервере:
&НаКлиенте
Процедура СтатусПриИзменении(Элемент)
Если Объект.Статус = ПредопределенноеЗначение("Перечисление.СтатусыЗаказов.Отменен") Тогда
Элементы.ПричинаОтмены.Видимость = Истина;
КонецЕсли;
КонецПроцедуры
В формах управляемого приложения это стандартный способ: так код не зависит от того, доступен ли нужный менеджер в контексте клиента. Та же функция возвращает предопределённые элементы справочников, поэтому код выглядит единообразно.
Пустая ссылка через эту функцию: ПредопределенноеЗначение("Перечисление.СтатусыЗаказов.ПустаяСсылка").
Способ 3. Параметром запроса
Значение передают в запрос так же, как любую ссылку:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Ссылка
|ИЗ
| Документ.ЗаказКлиента КАК Заказ
|ГДЕ
| Заказ.Статус = &Статус";
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыЗаказов.Выполнен);
Подходит, когда значение вычисляется в коде или приходит извне.
Способ 4. Функцией ЗНАЧЕНИЕ в тексте запроса
Когда значение известно заранее, его пишут прямо в текст. Подробно — в следующем разделе.
Способ 5. По имени из строки
Менеджер перечисления индексируется строкой с именем значения:
ИмяЗначения = "Выполнен";
Статус = Перечисления.СтатусыЗаказов[ИмяЗначения];
Так же индексируется и коллекция Перечисления — по имени самого перечисления. Это основа динамического доступа, о нём ниже.
| Способ | Где работает | Когда выбирать |
|---|---|---|
Перечисления.Имя.Значение | Сервер, модули объектов | Обычный серверный код |
ПредопределенноеЗначение("Перечисление.…") | Клиент и сервер | Модули форм, общие модули с клиентом |
Параметр &Статус | Запрос | Значение вычисляется в коде |
ЗНАЧЕНИЕ(Перечисление.…) | Текст запроса, СКД | Значение известно заранее |
Перечисления.Имя[Строка] | Сервер | Имя значения хранится в строке |
Как обращаться к перечислению в запросе 1С
ЗНАЧЕНИЕ() в условии
ВЫБРАТЬ
Реализация.Ссылка,
Реализация.СуммаДокумента
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРеализация.Товары)
Внутри скобок — только литерал. Параметр вида ЗНАЧЕНИЕ(&Вид) или выражение запрос не примет. Если значение меняется, используйте параметр.
Несколько значений перечисляют через В:
ГДЕ
Заказ.Статус В (ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.КОбеспечению),
ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.КОтгрузке))
Проверка на незаполненность:
ГДЕ
Заказ.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка)
Системные перечисления в запросе пишутся так же, без слова «Перечисление»: ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход).
Выборка всех значений из таблицы перечисления
У каждого перечисления есть таблица в языке запросов с полями Ссылка и Порядок:
ВЫБРАТЬ
Статусы.Ссылка КАК Статус,
ПРЕДСТАВЛЕНИЕ(Статусы.Ссылка) КАК Наименование
ИЗ
Перечисление.СтатусыЗаказов КАК Статусы
УПОРЯДОЧИТЬ ПО
Статусы.Порядок
Пригодится, чтобы получить полный список статусов и соединить его с остатками: тогда в отчёт попадут и статусы, по которым заказов нет.
Сортировка и представление
При УПОРЯДОЧИТЬ ПО Заказ.Статус записи сортируются по порядку значений в конфигураторе, а не по алфавиту синонимов. Нужна алфавитная сортировка — сортируйте по ПРЕДСТАВЛЕНИЕ(Заказ.Статус).
В системе компоновки данных (СКД) запрос с ЗНАЧЕНИЕ() работает без изменений. В отборах отчёта значение выбирают из списка, писать код не нужно.
Получение значения перечисления по строке, имени и индексу
Динамический доступ нужен, когда имя перечисления или значения приходит из настроек, файла загрузки, HTTP-запроса или формируется в универсальной процедуре.
Значение по имени перечисления и имени значения
ИмяПеречисления = "СтатусыЗаказов";
ИмяЗначения = "Выполнен";
Статус = Перечисления[ИмяПеречисления][ИмяЗначения];
// то же самое через строку, работает и на клиенте
Статус = ПредопределенноеЗначение("Перечисление." + ИмяПеречисления + "." + ИмяЗначения);
Перед обращением проверьте, что такое значение существует, иначе получите ошибку выполнения:
МетаПеречисление = Метаданные.Перечисления.Найти(ИмяПеречисления);
Если МетаПеречисление = Неопределено Тогда
ВызватьИсключение "Нет перечисления " + ИмяПеречисления;
КонецЕсли;
Если МетаПеречисление.ЗначенияПеречисления.Найти(ИмяЗначения) = Неопределено Тогда
ВызватьИсключение "Нет значения " + ИмяЗначения;
КонецЕсли;
Имя значения по ссылке
Обратная задача: есть ссылка, нужно её имя для кода (не синоним). Строка Строка(Статус) вернёт синоним, а он может быть переведён или переименован. Надёжный путь — через индекс и метаданные:
&НаСервереБезКонтекста
Функция ИмяЗначенияПеречисления(Значение)
МетаПеречисление = Значение.Метаданные();
Индекс = Перечисления[МетаПеречисление.Имя].Индекс(Значение);
Возврат МетаПеречисление.ЗначенияПеречисления[Индекс].Имя;
КонецФункции
В конфигурациях на БСП для этого есть готовая функция ОбщегоНазначения.ИмяЗначенияПеречисления(Значение), лучше взять её.
Значение по индексу
Метод Получить(Индекс) менеджера возвращает значение по позиции, отсчёт с нуля:
ПервыйСтатус = Перечисления.СтатусыЗаказов.Получить(0);
Индекс меняется, если разработчик переставит значения в конфигураторе. Не храните индексы в базе и файлах, храните имена.
Список значений для формы
Типовая задача — заполнить список выбора поля только частью значений и с собственными подписями:
&НаСервере
Процедура ЗаполнитьСписокСтатусов()
Список = Элементы.Статус.СписокВыбора;
Список.Очистить();
Для Каждого МетаЗначение Из Метаданные.Перечисления.СтатусыЗаказов.ЗначенияПеречисления Цикл
Если МетаЗначение.Имя = "Отменен" Тогда
Продолжить;
КонецЕсли;
Список.Добавить(Перечисления.СтатусыЗаказов[МетаЗначение.Имя], МетаЗначение.Синоним);
КонецЦикла;
КонецПроцедуры
Проверка типа значения: ТипЗнч(Значение) = Тип("ПеречислениеСсылка.СтатусыЗаказов"). Описание типа для реквизита формы или колонки таблицы: Новый ОписаниеТипов("ПеречислениеСсылка.СтатусыЗаказов").
Ошибки при обращении к перечислению и их причины
Выполнен. Откройте перечисление в конфигураторе, скопируйте имя на закладке «Данные», а не синоним из формы.Ещё несколько ловушек, которые не дают явной ошибки:
- 🌐 Сравнение по синониму.
Строка(Статус) = "Выполнен"сломается, как только синоним поправят или база запустится на другом языке интерфейса. - 📋 Составной тип. Если реквизит допускает несколько типов, пустое значение —
Неопределено. Здесь как раз помогаетЗначениеЗаполнено(), которая проверяет оба случая. - 🔀 Логика на порядке. Условие
Индекс(Статус) > 2«все статусы после отгрузки» тихо сломается при добавлении нового значения в середину списка. Перечисляйте нужные значения явно.
Расширения, обмены и производительность при работе с перечислениями
Перечисления в расширении конфигурации
Чтобы использовать перечисление основной конфигурации в коде расширения, его не обязательно заимствовать: обращение Перечисления.СтатусыЗаказов.Выполнен работает из модулей расширения как есть.
Заимствовать перечисление нужно, если вы добавляете в него собственные значения. Актуальные версии платформы 8.3 это позволяют. Добавленные значения существуют, пока подключено расширение. Если расширение отключить, реквизиты, где они записаны, получат битые ссылки.
Имена своих значений начинайте с префикса расширения, например мр_ОжидаетСогласования. Так при обновлении типовой не возникнет конфликта, если разработчики конфигурации добавят значение с тем же именем.
Перечисления в обменах данными
При выгрузке в XML через СериализаторXDTO и в правилах обмена значения перечислений передаются по имени. Отсюда два следствия:
- Переименование значения в одной базе ломает загрузку в другой: приёмник не найдёт значение с новым именем.
- Добавленное значение нужно добавить во всех базах обмена до того, как его начнут выбирать пользователи.
Если обмен самописный, держите таблицу соответствия имён и не передавайте синонимы — они меняются чаще.
Производительность
Обращение Перечисления.Имя.Значение не выполняет запрос к базе. Сравнение значений перечисления — сравнение ссылок, оно быстрое и в коде, и в условии ГДЕ.
Медленным код становится в двух местах:
- ⏱️ Разыменование в цикле.
Заказ.Статусу ссылки на документ читает документ из базы. Получите статусы одним запросом, а не по одному в цикле. - 🔍 Отбор без индекса. Условие по реквизиту-перечислению в большой таблице без индекса читает её целиком. Для частых отборов включите индексирование реквизита в конфигураторе.
Когда вместо перечисления лучше взять справочник
Перечисление хорошо там, где список значений привязан к алгоритмам. Код ветвится по каждому значению, и новое значение всё равно потребует доработки.
Если список меняется по бизнес-причинам, выбирайте другой объект:
| Задача | Что использовать | Почему |
|---|---|---|
| Пользователь сам добавляет значения | Справочник | Перечисление правит только разработчик в конфигураторе |
| Нужны реквизиты у значения (ставка, счёт, срок) | Справочник с предопределёнными элементами | У значения перечисления реквизитов нет |
| Часть значений фиксирована, часть добавляют пользователи | Справочник с предопределёнными элементами | К предопределённым обращаются из кода, остальные свободные |
| Набор свойств разного типа | План видов характеристик | Значения хранят свой тип |
| Список нужен только внутри одного алгоритма | Константа в коде, ФиксированнаяСтруктура | Не нужен объект метаданных и таблица в базе |
Переделать перечисление в справочник на работающей базе — это доработка с переносом данных: смена типа реквизитов, перезапись документов, правка запросов и обменов. Перед изменением структуры сделайте резервную копию базы.
Частые вопросы про обращение к перечислениям
Можно ли добавить значение перечисления в режиме «Предприятие»?
Как получить синоним значения перечисления в коде?
Строка(Значение) вернёт представление на текущем языке. Из метаданных: МетаЗначение.Синоним при обходе коллекции ЗначенияПеречисления.Работает ли обращение `Перечисления.Имя.Значение` во внешней обработке?
Метаданные.Перечисления.Найти().Как отобрать в запросе все значения, кроме одного?
Заказ.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Отменен). Пустые значения попадут в выборку, исключите их отдельным условием, если они не нужны.Что выводит `ЗначениеВСтрокуВнутр()` для значения перечисления?
ЗначениеИзСтрокиВнутр() в той же базе, но для обмена между базами надёжнее имя значения.