Разработчики платформы 1С:Предприятие 8 часто сталкиваются с необходимостью фильтрации или отбора данных на основе предопределенных значений. Использование перечислений в запросах позволяет писать типобезопасный код, который легче поддерживать и который не зависит от изменений в интерфейсе пользователя. Однако синтаксис работы с ними имеет свои нюансы, особенно когда речь заходит о ссылочных типах данных.

Неправильное обращение с объектами метаданных в тексте запроса может привести к ошибкам компиляции или, что хуже, к логическим ошибкам выполнения, когда система не может сопоставить строковое представление с реальным объектом. В этой статье мы детально разберем, как корректно использовать перечисления внутри конструкции ВЫБРАТЬ, как передавать их в параметры и как получать значения из полей таблиц.

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

Синтаксис использования перечислений в тексте запроса

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

Синтаксис выглядит следующим образом: ЗначениеПеречисления.ИмяПеречисления.ИмяЭлемента. Обратите внимание, что имя самого перечисления и имя его элемента разделяются точкой. Если вы попытаетесь написать просто имя элемента без префикса, система выдаст ошибку о неизвестном поле или идентификаторе.

Рассмотрим пример, где нам нужно отобрать документы только с определенным статусом. Предположим, у нас есть перечисление СтатусыЗаказов с элементом ВРаботе. Запрос будет выглядеть так:

ВЫБРАТЬ

Заказы.Ссылка,

Заказы.Номер

ИЗ

Документ.ЗаказКлиента КАК Заказы

ГДЕ

Заказы.Статус = ЗначениеПеречисления.СтатусыЗаказов.ВРаботе

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

💡

Используйте автоподстановку в редакторе кода (Ctrl+Space), чтобы не ошибиться в написании длинных имен перечислений и избежать опечаток в синтаксисе.

Важно отметить, что использование literals (констант) в запросе допустимо только тогда, когда значение известно на этапе написания кода. Если значение должно определяться динамически, следует использовать параметры.

Передача перечислений через параметры запроса

Более гибким и предпочтительным способом работы с данными является передача значений перечислений через параметры запроса. Это позволяет использовать один и тот же текст запроса для различных условий отбора, меняя лишь значения параметров перед выполнением.

Для объявления параметра в тексте запроса используется символ &. В коде программы, перед вызовом метода Выполнить(), необходимо установить значение этого параметра. Платформа автоматически выполнит приведение типов, если переменная содержит значение нужного перечисления.

  • 🔹 Объявите параметр в тексте запроса с префиксом &, например &ПараметрСтатус.
  • 🔹 Создайте объект Запрос и установите ему текст запроса.
  • 🔹 Получите объект параметров через метод Параметры.
  • 🔹 Установите значение, присвоив переменной конкретный элемент перечисления.

Пример реализации на встроенном языке:

ТекстЗапроса = "ВЫБРАТЬ Заказ.Ссылка ИЗ Документ.ЗаказКлиента КАК Заказ ГДЕ Заказ.Статус = &ПараметрСтатус";

Запрос = Новый Запрос(ТекстЗапроса);

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

Результат = Запрос.Выполнить();

Использование параметров не только упрощает поддержку кода, но и может положительно влиять на производительность, так как план выполнения запроса может кэшироваться сервером при повторных вызовах с разными значениями одного и того же параметра.

📊 Какой способ передачи данных в запрос вы используете чаще?
Прямое включение в текст
Через параметры
Через временные таблицы
Зависит от задачи

Приведение типов и работа со ссылками

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

В таких случаях прямое сравнение может не сработать или потребовать явного приведения типов. Если поле имеет тип СправочникСсылка, а вы пытаетесь сравнить его с перечислением, необходимо убедиться, что логика сравнения корректна. Часто требуется сначала получить значение из ссылки.

⚠️ Внимание: Попытка сравнить поле типа СправочникСсылка напрямую со значением перечисления без предварительного получения объекта или использования свойств может привести к ошибке выполнения или пустому результату выборки.

Для решения этой задачи можно использовать функцию ЗНАЧЕНИЕ в языке запросов или выполнять приведение типов в коде 1С перед передачей параметра. Если структура данных подразумевает хранение идентификатора перечисления в отдельном поле, убедитесь, что типы данных совпадают.

Рассмотрим таблицу, демонстрирующую распространенные типы полей и способы их сравнения с перечислениями:

Тип поля в БД Тип значения перечисления Способ сравнения Риск ошибки
ПеречислениеСсылка ПеречислениеСсылка Прямое равенство (=) Низкий
Строка ПеречислениеСсылка Сравнение с Именем (Ссылка.Имя) Высокий (зависит от локали)
Число ПеречислениеСсылка Сравнение с Порядком (Ссылка.Порядок) Средний (может измениться)
ХранилищеЗначения ПеречислениеСсылка Требуется извлечение значения Высокий

Наиболее надежным способом является хранение и сравнение именно ссылочных типов данных. Использование строковых представлений или порядковых номеров является устаревшей практикой и не рекомендуется к применению в новых разработках на платформе 1С:Предприятие 8.3 и выше.

Почему не стоит сравнивать по имени?

Сравнение по свойству .Имя зависит от языка интерфейса пользователя. Если база работает в многопользовательском режиме с разными языками, сравнение строк может дать неверный результат.

Получение значения перечисления из результата запроса

После выполнения запроса данные возвращаются в объекте Выборка. Для доступа к значению перечисления, хранящемуся в поле результата, используется стандартный синтаксис обращения к полям. Тип возвращаемого значения будет соответствовать типу поля в источнике данных.

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

Пример обработки результатов:

Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл

// Получаем ссылку на элемент перечисления

Статус = Выборка.Статус;

// Проверяем конкретное значение

Если Статус = Перечисления.СтатусыЗаказов.Выполнен Тогда

// Логика обработки выполненного заказа

КонецЕсли;

КонецЦикла;

В случаях, когда в запросе используется вычисляемое поле или агрегатная функция, тип результата может измениться. Всегда проверяйте тип данных возвращаемого поля, если вы формируете сложную выборку с использованием операторов ЕСТЬNULL или ВЫБОР.

💡

При чтении данных из выборки тип значения автоматически определяется платформой, однако явная проверка типа через Функция.ТипЗн() может помочь в отладке сложных запросов.

Обработка пустых значений и исключительных ситуаций

При работе с перечислениями в запросах важно учитывать возможность наличия пустых ссылок или значений NULL. В языке запросов 1С пустая ссылка на перечисление не эквивалентна значению NULL, но сравнение с ними требует осторожности.

Если поле в базе данных может не быть заполненным, использование оператора сравнения = с конкретным значением перечисления автоматически отсеет пустые значения. Однако, если вам нужно явно обработать случай отсутствия значения, используйте оператор ЕСТЬNULL.

  • 🔸 Оператор ЕСТЬNULL(Поле, ЗаменяющееЗначение) позволяет подставить дефолтное значение.
  • 🔸 Условие ГДЕ Поле ЕСТЬ NULL отберет только строки с пустым значением.
  • 🔸 Сравнение Поле = ЗначениеПеречисления... игнорирует строки, где поле пусто.

Частой ошибкой является попытка вызвать методы объекта перечисления, когда переменная содержит Неопределено. Перед обращением к свойствам ссылки убедитесь, что значение корректно инициализировано.

⚠️ Внимание: В запросах с объединениями (ОБЪЕДИНИТЬ ВСЕ) типы полей в разных частях запроса должны быть совместимы. Если в одной части возвращается перечисление, а в другой — пустое значение, убедитесь, что система корректно определяет общий тип.

Для защиты от ошибок выполнения рекомендуется использовать конструкцию Попытка...Исключение при обработке результатов, если источник данных может содержать некорректные ссылки, хотя для штатных перечислений это редкость.

☑️ Проверка безопасности работы с перечислениями

Выполнено: 0 / 4

Оптимизация производительности при фильтрации

Использование перечислений в условиях отбора (ГДЕ) является эффективным способом фильтрации данных, так как сравнение ссылок выполняется быстро. Однако, если таблица содержит миллионы записей, структура индексов играет решающую роль.

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

Также стоит избегать использования функций над полями в условии ГДЕ. Например, конструкция ГДЕ Строка(Заказы.Статус) = "ВРаботе" запретит использование индекса. Всегда сравнивайте поле напрямую со значением перечисления.

Если вы используете динамический список или СКД (Систему Компоновки Данных), настройка отборов через перечисления также должна опираться на индексируемые поля. В настройках СКД убедитесь, что тип отбора установлен в соответствие с типом данных поля.

Влияние locking на производительность

При выборке больших объемов данных с фильтрацией по перечислениям в режиме предприятия может возникать блокировка записей. Используйте флаг ТОЛЬКО ДЛЯ ЧТЕНИЯ в запросе, если данные не будут изменяться.

Можно ли использовать перечисления в виртуальных таблях регистров?

Да, перечисления можно использовать в условиях отбора виртуальных таблиц (срезы, остатки). Синтаксис остается тем же: ЗначениеПеречисления.Имя.Элемент. Важно лишь учитывать, что виртуальные таблицы могут иметь свои особенности формирования итогов.

Что делать, если имя перечисления изменилось в конфигурации?

Если вы использовали прямое включение в текст запроса, код потребует перекомпиляции и исправления имен. Если использовались параметры, то достаточно обновить код установки параметров. Использование синонимов в запросах не поддерживается для имен метаданных.

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

Для этого не нужен запрос к базе данных. Используйте объект Перечисления в коде: Для каждого Элемент Из Перечисления.ИмяПеречисления Цикл ... КонецЦикла. Это работает быстрее и не нагружает СУБД.

Допустимо ли хранить порядковый номер перечисления в базе?

Нет, это плохая практика. Порядок элементов может измениться при обновлении конфигурации. Всегда храните и используйте ссылки на объекты метаданных или их уникальные идентификаторы (GUID), если требуется сериализация.

Работает ли автоподстановка перечислений в консоли запросов?

Да, консоль запросов поддерживает автоподстановку объектов метаданных. Начните вводить ЗначениеПеречисления и нажмите Ctrl+Space для выбора нужного элемента из дерева метаданных текущей базы.