Перечисления в конфигурации 1С 8.3: когда фиксированный список лучше справочника

· 9 мин

Содержание

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

Частое заблуждение — считать перечисление «маленьким справочником». Это не так. У перечисления нет реквизитов, табличных частей, иерархии и кодов. Зато на каждое значение можно опереться в коде, и оно гарантированно существует в любой базе на этой конфигурации.

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

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

ПризнакПеречислениеСправочник
Кто создаёт значенияРазработчик в конфигуратореПользователь в режиме «Предприятие» (плюс предопределённые элементы)
Реквизиты и табличные частиНетЕсть
Иерархия, код, наименованиеНетЕсть
Изменить состав значенийТолько через изменение конфигурации и обновление базыВ любой момент, без конфигуратора
Обращение из кодаПеречисления.ВидыОплаты.НаличныеСправочники.Валюты.НайтиПоКоду("643") или предопределённый элемент
Пометка удаленияНетЕсть

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

Что можно настроить у перечисления

  • 🏷️ Значения — у каждого есть имя (для кода), синоним (его видит пользователь) и комментарий.
  • 📋 Формы — списка и выбора, если стандартных не хватает.
  • 🔢 Порядок значений — задаётся перестановкой в списке значений и влияет на сортировку.
  • 🧩 Команды и макеты — как у других прикладных объектов.

Как перечисление хранится в базе данных

В клиент-серверной базе каждому перечислению соответствует таблица с именем вида _Enum123. В ней всего две колонки:

  • _IDRRef — уникальный идентификатор значения (16 байт). На него ссылаются реквизиты документов и справочников.
  • _EnumOrder — порядковый номер значения в том порядке, в каком оно стоит в конфигураторе.

Имена и синонимы значений в таблице не хранятся. Они лежат в метаданных конфигурации. Отсюда три практических следствия:

  1. Сменили синоним или переименовали значение — данные в базе не меняются, ссылки остаются рабочими. Сломается только код, где упоминалось старое имя.
  2. Поменяли местами значения — меняется _EnumOrder, и сортировка по этому полю пойдёт в новом порядке.
  3. Удалили значение, на которое есть ссылки в данных — в документах появится битая ссылка <Объект не найден>. Обратно её не вернуть простым добавлением значения с тем же именем: у нового значения будет другой идентификатор.

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

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

Когда выбирать перечисление, а когда — нет

Простое правило: если от значения зависит алгоритм — это перечисление. Если от значения зависят только данные — это справочник.

Перечисление подходит, если

  • ✅ Вариантов мало, и они не меняются годами: «Юридическое лицо / Физическое лицо», «Приход / Расход».
  • ✅ В коде есть ветвление по значению: при «Предоплате» документ ведёт себя одним образом, при «Постоплате» — другим.
  • ✅ Пользователь не должен заводить свои варианты: новый вариант без доработки кода всё равно ничего не будет делать.
  • ✅ Нужен короткий и предсказуемый список для отбора в отчётах.

Справочник лучше, если

  • ❌ Значению нужны свойства: ставка, срок, ответственный, счёт учёта.
  • ❌ Список пополняется по мере работы: склады, причины возврата, виды продукции.
  • ❌ Разные клиенты конфигурации захотят разный набор вариантов.

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

Что выбрать для вашего списка значений?

Примеры применения перечислений в конфигурации

Статус заявки

Перечисление СтатусыЗаявок со значениями Новая, ВРаботе, Выполнена, Отменена. Реквизит Статус в документе «Заявка» имеет тип ПеречислениеСсылка.СтатусыЗаявок. В модуле объекта легко запретить проведение отменённой заявки:

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

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

    // формирование движений

КонецПроцедуры

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

Вид контрагента

Перечисление с двумя значениями управляет видимостью полей формы: для юрлица показываем КПП, для физлица — паспортные данные.

&НаКлиенте
Процедура ВидКонтрагентаПриИзменении(Элемент)
    ОбновитьВидимость();
КонецПроцедуры

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

Параметр обработки или отчёта

Перечисление ПериодичностьОтчета (День, Неделя, Месяц) в реквизите обработки даёт пользователю аккуратный выпадающий список вместо свободного ввода. Ошибиться с вводом становится невозможно.

Измерение регистра

Перечисление часто становится измерением регистра накопления или сведений. Пример: регистр «Расчёты с клиентами» с измерением ВидРасчета (Аванс, Долг). Итоги по такому измерению получаются компактными: значений два, срез по каждому строится одним запросом к виртуальной таблице остатков.

Тот же приём работает для регистра сведений с настройками. Измерение ВидУведомления типа перечисления плюс ресурс Включено — и у каждого пользователя своя таблица флажков без отдельного справочника. Так же решают задачу «свойства значения перечисления»: ставку, счёт или срок кладут в регистр сведений, где измерение — само перечисление.

Составной тип

Перечисление можно включить в составной тип реквизита. Например, «Значение условия» хранит либо ссылку на номенклатуру, либо значение перечисления «Любая номенклатура». Пользуйтесь этим аккуратно: составной тип усложняет запросы.

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

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

Внутри запроса значение перечисления указывают через функцию ЗНАЧЕНИЕ():

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

Сортировка по полю перечисления идёт по порядку значений из конфигуратора, а не по алфавиту синонимов. Это удобно: статусы выстроятся в жизненный цикл «Новая → В работе → Выполнена».

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

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

Запрос.Текст = "... ГДЕ Заявка.Статус В (&Статусы)";
Статусы = Новый Массив;
Статусы.Добавить(Перечисления.СтатусыЗаявок.Новая);
Статусы.Добавить(Перечисления.СтатусыЗаявок.ВРаботе);
Запрос.УстановитьПараметр("Статусы", Статусы);

Клиент и сервер

Свойство глобального контекста Перечисления в тонком и веб-клиенте недоступно. Поэтому в процедуре с директивой &НаКлиенте запись Перечисления.ВидыКонтрагентов.ЮрЛицо вызовет ошибку. На клиенте используют ПредопределенноеЗначение("Перечисление.ВидыКонтрагентов.ЮрЛицо") — функция возвращает ссылку без серверного вызова.

На сервере обе формы записи работают, но короче и привычнее Перечисления.Имя.Значение.

Имя, индекс и обход значений

Менеджер перечисления умеет немного, но этого хватает:

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

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

// Имя значения, как в конфигураторе
ИмяЗначения = Метаданные.Перечисления.СтатусыЗаявок.ЗначенияПеречисления[Индекс].Имя;

// Обход всех значений
Для Каждого ЗначениеСтатуса Из Перечисления.СтатусыЗаявок Цикл
    Сообщить(ЗначениеСтатуса);
КонецЦикла;

Для имени есть и короткий путь: XMLСтрока(Статус) возвращает имя значения (Отменена). Им удобно пользоваться при обмене данными и записи значения в JSON.

💡 Синоним значения — это представление для пользователя. Имя — технический идентификатор. В файлах обмена и интеграциях передавайте имя: синоним может измениться при очередной правке интерфейса.

Ошибки, которые чаще всего делают с перечислениями

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

Ещё одна тонкость — логика по индексу. Код вида Если Перечисления.СтатусыЗаявок.Индекс(Статус) > 1 ломается молча, когда кто-то вставляет новое значение в середину списка. Сравнивайте значения явно или держите порядок под контролем комментарием в модуле.

Как ускорить и упростить работу с перечислениями

Значение перечисления — обычная ссылка размером 16 байт. Сами по себе перечисления не тормозят. Проблемы создаёт то, как с ними обращаются.

  • ⚡ Не фильтруйте по представлению. Условие ГДЕ ПРЕДСТАВЛЕНИЕ(Заявка.Статус) = "Новая" не использует индекс и зависит от синонима. Фильтр по ЗНАЧЕНИЕ() или по параметру работает быстрее и надёжнее.
  • 📇 Индексируйте реквизит, если по нему часто отбирают. Для реквизита-статуса в большой таблице документов включите свойство «Индексировать» — отбор «все невыполненные заявки» перестанет сканировать таблицу целиком.
  • 🔗 Не соединяйте запрос с таблицей перечисления без нужды. Чтобы получить синоним, достаточно ПРЕДСТАВЛЕНИЕ(Поле), соединение с Перечисление.Имя здесь лишнее.
  • 🧮 Вычисляйте ссылку один раз. В цикле на тысячи строк вынесите ПредопределенноеЗначение(...) или Перечисления.Имя.Значение в переменную до цикла.
  • 🗂️ Группируйте проверки. Вместо цепочки Статус = А Или Статус = Б Или Статус = В в коде храните массив допустимых значений и проверяйте Массив.Найти(Статус) <> Неопределено, а в запросе используйте В (&Статусы).

Что проверить перед изменением перечисления

Перед правкой перечисления в рабочей конфигурации
Выполнено: 0 / 6

Если конфигурация типовая и стоит на поддержке, свои значения в её перечисления лучше не добавлять напрямую: при обновлении это усложнит сравнение и объединение. Создайте собственное перечисление в расширении или в отдельной ветке доработок.

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

Можно ли добавить значение перечисления в режиме «Предприятие»?
Нет. Состав значений меняется только в конфигураторе, после чего нужно обновить конфигурацию базы данных. Если варианты должен добавлять пользователь, нужен справочник.
Можно ли добавить реквизит к значению перечисления?
Нет, у перечисления реквизитов не бывает. Свойства значения хранят в регистре сведений с измерением этого типа или переходят на справочник с предопределёнными элементами.
Сколько значений может быть в перечислении?
Жёсткого практического ограничения нет, но список из десятков значений неудобно выбирать в форме. Если значений больше 15–20, проверьте, не справочник ли это по сути.
Что вернёт пустое значение перечисления при выводе на экран?
Пустую строку. В коде пустое значение проверяют сравнением с Перечисления.Имя.ПустаяСсылка() или методом ЗначениеЗаполнено().
Как получить значение перечисления по его имени из строки?
На сервере — Перечисления.СтатусыЗаявок[ИмяЗначения], где ИмяЗначения — строка с именем, например "Отменена". На клиенте — ПредопределенноеЗначение("Перечисление.СтатусыЗаявок." + ИмяЗначения).