Перечисления в конфигурации 1С 8.3: когда фиксированный список лучше справочника
Содержание
Перечисление в 1С — это объект конфигурации с постоянным набором значений, который задаёт разработчик в конфигураторе. Пользователь в режиме «Предприятие» не может добавить, удалить или переименовать значение перечисления. Поэтому объект применяют там, где список вариантов зашит в логику программы: вид контрагента, способ оплаты, статус заявки.
Частое заблуждение — считать перечисление «маленьким справочником». Это не так. У перечисления нет реквизитов, табличных частей, иерархии и кодов. Зато на каждое значение можно опереться в коде, и оно гарантированно существует в любой базе на этой конфигурации.
Чем перечисление отличается от справочника
Оба объекта дают ссылочный тип, и в форме оба выглядят как поле выбора из списка. На этом сходство заканчивается.
| Признак | Перечисление | Справочник |
|---|---|---|
| Кто создаёт значения | Разработчик в конфигураторе | Пользователь в режиме «Предприятие» (плюс предопределённые элементы) |
| Реквизиты и табличные части | Нет | Есть |
| Иерархия, код, наименование | Нет | Есть |
| Изменить состав значений | Только через изменение конфигурации и обновление базы | В любой момент, без конфигуратора |
| Обращение из кода | Перечисления.ВидыОплаты.Наличные | Справочники.Валюты.НайтиПоКоду("643") или предопределённый элемент |
| Пометка удаления | Нет | Есть |
Отдельно стоят системные перечисления платформы: ВидДвиженияНакопления, РежимЗаписиДокумента, ВидСчета и другие. Их нет в дереве метаданных, они встроены в платформу и описаны в синтаксис-помощнике. Прикладные перечисления, о которых идёт речь здесь, создаёт разработчик: ветка Перечисления в дереве конфигурации, команда «Добавить».
Что можно настроить у перечисления
- 🏷️ Значения — у каждого есть имя (для кода), синоним (его видит пользователь) и комментарий.
- 📋 Формы — списка и выбора, если стандартных не хватает.
- 🔢 Порядок значений — задаётся перестановкой в списке значений и влияет на сортировку.
- 🧩 Команды и макеты — как у других прикладных объектов.
Как перечисление хранится в базе данных
В клиент-серверной базе каждому перечислению соответствует таблица с именем вида _Enum123. В ней всего две колонки:
_IDRRef— уникальный идентификатор значения (16 байт). На него ссылаются реквизиты документов и справочников._EnumOrder— порядковый номер значения в том порядке, в каком оно стоит в конфигураторе.
Имена и синонимы значений в таблице не хранятся. Они лежат в метаданных конфигурации. Отсюда три практических следствия:
- Сменили синоним или переименовали значение — данные в базе не меняются, ссылки остаются рабочими. Сломается только код, где упоминалось старое имя.
- Поменяли местами значения — меняется
_EnumOrder, и сортировка по этому полю пойдёт в новом порядке. - Удалили значение, на которое есть ссылки в данных — в документах появится битая ссылка
<Объект не найден>. Обратно её не вернуть простым добавлением значения с тем же именем: у нового значения будет другой идентификатор.
Перед удалением значения перечисления найдите все ссылки на него в данных запросом по реквизитам этого типа и замените их на другое значение. Только потом обновляйте конфигурацию.
В файловой базе принцип тот же, хотя физический формат хранения другой.
Когда выбирать перечисление, а когда — нет
Простое правило: если от значения зависит алгоритм — это перечисление. Если от значения зависят только данные — это справочник.
Перечисление подходит, если
- ✅ Вариантов мало, и они не меняются годами: «Юридическое лицо / Физическое лицо», «Приход / Расход».
- ✅ В коде есть ветвление по значению: при «Предоплате» документ ведёт себя одним образом, при «Постоплате» — другим.
- ✅ Пользователь не должен заводить свои варианты: новый вариант без доработки кода всё равно ничего не будет делать.
- ✅ Нужен короткий и предсказуемый список для отбора в отчётах.
Справочник лучше, если
- ❌ Значению нужны свойства: ставка, срок, ответственный, счёт учёта.
- ❌ Список пополняется по мере работы: склады, причины возврата, виды продукции.
- ❌ Разные клиенты конфигурации захотят разный набор вариантов.
Промежуточный вариант — справочник с предопределёнными элементами. Код опирается на предопределённый элемент так же надёжно, как на значение перечисления, но у элемента есть реквизиты, а пользователь может добавить свои элементы рядом.
Перечисления.Имя.Значение.Примеры применения перечислений в конфигурации
Статус заявки
Перечисление СтатусыЗаявок со значениями Новая, ВРаботе, Выполнена, Отменена. Реквизит Статус в документе «Заявка» имеет тип ПеречислениеСсылка.СтатусыЗаявок. В модуле объекта легко запретить проведение отменённой заявки:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Если Статус = Перечисления.СтатусыЗаявок.Отменена Тогда
ОбщегоНазначения.СообщитьПользователю("Отменённую заявку провести нельзя.");
Отказ = Истина;
Возврат;
КонецЕсли;
// формирование движений
КонецПроцедуры
ОбщегоНазначения.СообщитьПользователю — функция Библиотеки стандартных подсистем. В конфигурации без БСП используйте объект СообщениеПользователю.
Вид контрагента
Перечисление с двумя значениями управляет видимостью полей формы: для юрлица показываем КПП, для физлица — паспортные данные.
&НаКлиенте
Процедура ВидКонтрагентаПриИзменении(Элемент)
ОбновитьВидимость();
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьВидимость()
ЭтоЮрЛицо = (Объект.ВидКонтрагента = ПредопределенноеЗначение("Перечисление.ВидыКонтрагентов.ЮрЛицо"));
Элементы.КПП.Видимость = ЭтоЮрЛицо;
Элементы.ПаспортныеДанные.Видимость = Не ЭтоЮрЛицо;
КонецПроцедуры
Параметр обработки или отчёта
Перечисление ПериодичностьОтчета (День, Неделя, Месяц) в реквизите обработки даёт пользователю аккуратный выпадающий список вместо свободного ввода. Ошибиться с вводом становится невозможно.
Измерение регистра
Перечисление часто становится измерением регистра накопления или сведений. Пример: регистр «Расчёты с клиентами» с измерением ВидРасчета (Аванс, Долг). Итоги по такому измерению получаются компактными: значений два, срез по каждому строится одним запросом к виртуальной таблице остатков.
Тот же приём работает для регистра сведений с настройками. Измерение ВидУведомления типа перечисления плюс ресурс Включено — и у каждого пользователя своя таблица флажков без отдельного справочника. Так же решают задачу «свойства значения перечисления»: ставку, счёт или срок кладут в регистр сведений, где измерение — само перечисление.
Составной тип
Перечисление можно включить в составной тип реквизита. Например, «Значение условия» хранит либо ссылку на номенклатуру, либо значение перечисления «Любая номенклатура». Пользуйтесь этим аккуратно: составной тип усложняет запросы.
Перечисления в запросах и в клиентском коде
Значение в тексте запроса
Внутри запроса значение перечисления указывают через функцию ЗНАЧЕНИЕ():
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заявка.Ссылка,
| Заявка.Статус,
| ПРЕДСТАВЛЕНИЕ(Заявка.Статус) КАК СтатусТекстом
|ИЗ
| Документ.Заявка КАК Заявка
|ГДЕ
| Заявка.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаявок.Отменена)
|УПОРЯДОЧИТЬ ПО
| Заявка.Статус";
Сортировка по полю перечисления идёт по порядку значений из конфигуратора, а не по алфавиту синонимов. Это удобно: статусы выстроятся в жизненный цикл «Новая → В работе → Выполнена».
Пустое значение в запросе — ЗНАЧЕНИЕ(Перечисление.СтатусыЗаявок.ПустаяСсылка).
Если значений для отбора несколько или они вычисляются в коде, передайте их параметром:
Запрос.Текст = "... ГДЕ Заявка.Статус В (&Статусы)";
Статусы = Новый Массив;
Статусы.Добавить(Перечисления.СтатусыЗаявок.Новая);
Статусы.Добавить(Перечисления.СтатусыЗаявок.ВРаботе);
Запрос.УстановитьПараметр("Статусы", Статусы);
Клиент и сервер
Свойство глобального контекста Перечисления в тонком и веб-клиенте недоступно. Поэтому в процедуре с директивой &НаКлиенте запись Перечисления.ВидыКонтрагентов.ЮрЛицо вызовет ошибку. На клиенте используют ПредопределенноеЗначение("Перечисление.ВидыКонтрагентов.ЮрЛицо") — функция возвращает ссылку без серверного вызова.
На сервере обе формы записи работают, но короче и привычнее Перечисления.Имя.Значение.
Имя, индекс и обход значений
Менеджер перечисления умеет немного, но этого хватает:
// Порядковый номер значения (с нуля)
Индекс = Перечисления.СтатусыЗаявок.Индекс(Статус);
// Значение по номеру
ПервыйСтатус = Перечисления.СтатусыЗаявок.Получить(0);
// Имя значения, как в конфигураторе
ИмяЗначения = Метаданные.Перечисления.СтатусыЗаявок.ЗначенияПеречисления[Индекс].Имя;
// Обход всех значений
Для Каждого ЗначениеСтатуса Из Перечисления.СтатусыЗаявок Цикл
Сообщить(ЗначениеСтатуса);
КонецЦикла;
Для имени есть и короткий путь: XMLСтрока(Статус) возвращает имя значения (Отменена). Им удобно пользоваться при обмене данными и записи значения в JSON.
💡 Синоним значения — это представление для пользователя. Имя — технический идентификатор. В файлах обмена и интеграциях передавайте имя: синоним может измениться при очередной правке интерфейса.
Ошибки, которые чаще всего делают с перечислениями
Если Строка(Статус) = "В работе". После правки синонима на «В работе у исполнителя» сравнение ломается. Сравнивайте ссылки: Статус = Перечисления.СтатусыЗаявок.ВРаботе.ЗНАЧЕНИЕ() проверяется при выполнении запроса, а не при синтаксическом контроле модуля. Найдите старое имя глобальным поиском по конфигурации.Перечисления из процедуры &НаКлиенте. Замените на ПредопределенноеЗначение("Перечисление.Имя.Значение").Ещё одна тонкость — логика по индексу. Код вида Если Перечисления.СтатусыЗаявок.Индекс(Статус) > 1 ломается молча, когда кто-то вставляет новое значение в середину списка. Сравнивайте значения явно или держите порядок под контролем комментарием в модуле.
Как ускорить и упростить работу с перечислениями
Значение перечисления — обычная ссылка размером 16 байт. Сами по себе перечисления не тормозят. Проблемы создаёт то, как с ними обращаются.
- ⚡ Не фильтруйте по представлению. Условие
ГДЕ ПРЕДСТАВЛЕНИЕ(Заявка.Статус) = "Новая"не использует индекс и зависит от синонима. Фильтр поЗНАЧЕНИЕ()или по параметру работает быстрее и надёжнее. - 📇 Индексируйте реквизит, если по нему часто отбирают. Для реквизита-статуса в большой таблице документов включите свойство «Индексировать» — отбор «все невыполненные заявки» перестанет сканировать таблицу целиком.
- 🔗 Не соединяйте запрос с таблицей перечисления без нужды. Чтобы получить синоним, достаточно
ПРЕДСТАВЛЕНИЕ(Поле), соединение сПеречисление.Имяздесь лишнее. - 🧮 Вычисляйте ссылку один раз. В цикле на тысячи строк вынесите
ПредопределенноеЗначение(...)илиПеречисления.Имя.Значениев переменную до цикла. - 🗂️ Группируйте проверки. Вместо цепочки
Статус = А Или Статус = Б Или Статус = Вв коде храните массив допустимых значений и проверяйтеМассив.Найти(Статус) <> Неопределено, а в запросе используйтеВ (&Статусы).
Что проверить перед изменением перечисления
Если конфигурация типовая и стоит на поддержке, свои значения в её перечисления лучше не добавлять напрямую: при обновлении это усложнит сравнение и объединение. Создайте собственное перечисление в расширении или в отдельной ветке доработок.
Частые вопросы
Можно ли добавить значение перечисления в режиме «Предприятие»?
Можно ли добавить реквизит к значению перечисления?
Сколько значений может быть в перечислении?
Что вернёт пустое значение перечисления при выводе на экран?
Перечисления.Имя.ПустаяСсылка() или методом ЗначениеЗаполнено().Как получить значение перечисления по его имени из строки?
Перечисления.СтатусыЗаявок[ИмяЗначения], где ИмяЗначения — строка с именем, например "Отменена". На клиенте — ПредопределенноеЗначение("Перечисление.СтатусыЗаявок." + ИмяЗначения).