Разработчики платформы 1С:Предприятие 8 часто сталкиваются с необходимостью выборки данных по конкретным статусам или видам объектов. Наиболее частая ситуация — использование значения типа Перечисление в тексте запроса. Понимание того, как система интерпретирует строковые литералы в контексте ссылочных типов, критически важно для написания корректного и производительного кода.
В отличие от примитивных типов данных, таких как Число или Строка, перечисления являются ссылочными типами. Это означает, что при указании имени элемента перечисления в кавычках, например "ВЧерновике", система 1С выполняет неявное преобразование. Она ищет соответствующий элемент в метаданных и подставляет его уникальную ссылку (UUID) в результирующий SQL-запрос к базе данных.
Однако существуют нюансы, связанные с локализацией, версионностью конфигурации и особенностями синтаксиса. Неправильное использование строковых представлений может привести к ошибкам выполнения или, что хуже, к некорректной фильтрации данных при смене языка интерфейса. Разберем детально механизмы работы и лучшие практики.
Механизм неявного преобразования типов
Когда вы пишете запрос на встроенном языке 1С, движок запросов анализирует структуру перед отправкой в СУБД. Если в условии ГДЕ или в списке выбора встречается строка, совпадающая с именем элемента перечисления, происходит маппинг. Система находит объект метаданных Перечисление.СтатусыДокумента и заменяет строку на внутреннюю ссылку.
Этот процесс прозрачен для разработчика, но требует понимания того, что в итоговом SQL-запросе, уходящем в MS SQL Server или PostgreSQL, строки уже не будет. Там будет бинарный идентификатор. Именно поэтому запросы с перечислениями работают быстрее, чем запросы с явным приведением типов через функции.
⚠️ Внимание: Если имя элемента перечисления содержит пробелы или специальные символы, использование строкового литерала может стать проблематичным. В таких случаях всегда используйте явное обращение через конструктор объекта.
Рассмотрим пример, где преобразование происходит автоматически. Допустим, у нас есть справочник Номенклатура с реквизитом ВидНоменклатуры, который является перечислением.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ВидНоменклатуры = "Товар"
В данном случае строка "Товар" будет заменена на ссылку на элемент перечисления ВидыНоменклатуры.Товар. Это стандартное поведение платформы, которое упрощает чтение кода.
Используйте автоподстановку в редакторе запросов (Ctrl+Space), чтобы система сама подставила правильное имя перечисления, исключая опечатки в строковых литералах.
Сравнение строкового представления и констант
Существует два основных подхода к использованию перечислений в запросах: через строковые литералы и через глобальные константы. Хотя первый способ короче, второй считается более надежным и предпочтительным в профессиональной разработке на 1С.
Использование строки "Проведен" жестко привязывает ваш код к имени элемента. Если администратор конфигурации переименует элемент перечисления в метаданных (например, в "Проведенный"), ваш запрос перестанет работать или начнет возвращать пустой результат. Константы же привязаны к синонимам или внутренним именам, которые меняются реже, а при изменении структуры код часто подсвечивается редактором.
| Критерий | Строковый литерал | Глобальная константа | Конструктор объекта |
|---|---|---|---|
| Читаемость | Высокая | Средняя | Низкая |
| Защита от рефакторинга | Низкая | Высокая | Высокая |
| Производительность | Высокая | Высокая | Высокая |
| Зависимость от языка | Есть (синоним) | Нет | Нет |
При использовании констант код становится более явным. Вы сразу видите, к какому именно объекту метаданных идет обращение, не гадая, из какого перечисления взята строка "Черновик".
Работа в условиях WHERE и JOIN
Фильтрация записей по значению перечисления — самая распространенная операция. В условии ГДЕ можно использовать как одиночное значение, так и список значений. Важно помнить о типизации полей в объединяемых таблицах.
Если вы используете оператор В (IN), убедитесь, что все элементы списка относятся к одному и тому же типу перечисления. Смешивание разных типов приведет к ошибке компиляции запроса. Платформа строго следит за соответствием типов данных в условиях сравнения.
ВЫБРАТЬ
Документы.РеализацияТоваровУслуг.Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК Документы
ГДЕ
Документы.Статус В ("ВЧерновике", "НаСогласовании")
В сложных запросах с соединениями (ЛЕВОЕ СОЕДИНЕНИЕ) тип поля соединения должен совпадать. Если вы соединяете таблицу документов с виртуальной таблицей или другой таблицей, где статус хранится иначе, может потребоваться явное приведение типа.
⚠️ Внимание: При соединении таблиц убедитесь, что поле статуса в обеих таблицах имеет тип ПеречислениеСсылка. Соединение по строковому представлению (через функцию Представление) убьет производительность запроса.
Также стоит учитывать, что фильтрация по перечислениям обычно эффективно использует индексы базы данных, так как сравниваются бинарные ссылки, а не длинные строки. Это делает такие запросы быстрыми даже на больших объемах данных.
☑️ Оптимизация запроса с перечислением
Влияние локализации и синонимов
Один из самых коварных аспектов использования строковых представлений перечислений — зависимость от языка базы данных или интерфейса. Строковый литерал в запросе 1С интерпретируется в соответствии с текущим языком сеанса или языком базы данных, если запрос выполняется на сервере без явного контекста.
Если ваша конфигурация поддерживает несколько языков (например, русский и английский), и вы жестко прописали "Approved" в коде, то при переключении пользователя на русский язык этот запрос может перестать находить объекты, если внутренняя логика подстановки опирается на синонимы текущего языка.
Однако, в большинстве случаев сервер 1С использует внутренние имена или универсальные идентификаторы для разрешения строковых констант в запросах, отправляемых на выполнение. Тем не менее, полагаться на это рискованно. Изменение синонима элемента перечисления в конфигураторе не должно ломать работающий код, но при использовании строк это возможно.
⚠️ Внимание: Никогда не используйте переводные строки для фильтрации в запросах, которые выполняются в фоновых заданиях или на разных языковых локалях сервера. Это может привести к потере данных при обработке.
Для кросс-языковой совместимости лучше всего использовать константы типа Перечисления.Статусы.Утвержден. Они не зависят от того, как элемент называется в интерфейсе пользователя.
Как проверить язык подстановки?
Выполните запрос в консоли запросов с разным выбранным языком интерфейса. Если результат меняется — вы используете зависимые от языка строки.
Получение списка значений перечисления
Иногда возникает задача не отфильтровать данные, а получить сам список всех возможных значений перечисления внутри запроса. Стандартными средствами языка запросов 1С это сделать напрямую нельзя, так как перечисления не являются таблицами в базе данных.
Для решения этой задачи программисты используют временные таблицы или виртуальные таблицы, если они предусмотрены конфигурацией. Однако, чаще всего список значений формируется в коде и передается в запрос как параметр.
Если вам нужно вывести все статусы для построения отчета, используйте следующий подход: создайте временную таблицу и заполните её значениями из объекта перечисления в цикле. Это позволяет унифицировать обработку и использовать результат в дальнейших соединениях.
- 📋 Создайте временную таблицу с колонкой типа ПеречислениеСсылка.
- 🔄 Пройдитесь циклом по коллекции
Перечисления.ИмяПеречисления. - 💾 Загрузите значения во временную таблицу для использования в запросе.
Такой метод гарантирует, что вы получите актуальный список значений, даже если в метаданные были добавлены новые элементы после последней компиляции модуля.
Частые ошибки и отладка
При работе с перечислениями в строках запросов разработчики часто допускают типичные ошибки. Самая распространенная — опечатка в имени элемента. В отличие от кода на встроенном языке, где опечатка вызовет ошибку компиляции, в тексте запроса неверная строка может просто не найти ни одной записи, и ошибка обнаружится только при тестировании.
Другая частая проблема — попытка сравнить перечисление с пустой строкой. Пустая ссылка на перечисление не равна пустой строке. Для проверки на неопределенное значение используйте конструкцию ЕСТЬ NULL или сравнение с неопределенным значением типа.
Всегда проверяйте запрос на наличие записей при использовании новых или редко используемых элементов перечисления. "Молчаливая" ошибка (пустой результат) опаснее явной ошибки выполнения.
Для отладки используйте консоль запросов. Выведите тип параметра и его значение перед выполнением. Убедитесь, что система корректно распознает строку как ссылку. Если запрос работает медленно, проверьте, не происходит ли неявное преобразование типов, которое мешает использованию индекса.
FAQ: Вопросы и ответы
Можно ли использовать переменную со строкой вместо литерала в запросе?
Да, вы можете передать значение перечисления как параметр запроса. В коде 1С присвойте параметру значение элемента перечисления (не строку, а именно объект). Например: Запрос.УстановитьПараметр("Статус", Перечисления.Статусы.Новый). В тексте запроса используйте &Статус.
Что будет, если элемент перечисления удален из метаданных?
Если вы используете строковый литерал, запрос выполнится, но не найдет записей (так как ссылки в базе данных останутся, но маппинг имени не сработает или укажет на несуществующий объект). Если использовалась константа, код не скомпилируется или выдаст ошибку при запуске. Рекомендуется проводить очистку ссылок на удаленные элементы.
Как получить имя элемента перечисления из запроса?
В самом запросе вы можете выбрать поле Представление или использовать функцию ПРЕДСТАВЛЕНИЕ() в списке выбираемых полей. Это вернет строковое наименование (синоним) элемента, соответствующее текущему языку пользователя.
Влияет ли регистр символов в строке перечисления?
Да, при использовании строковых литералов в запросах 1С регистр обычно важен, так как сравнение идет по синонимам метаданных. Однако платформа может быть настроена на регистронезависимое сравнение в некоторых контекстах. Чтобы избежать проблем, соблюдайте регистр, указанный в конфигураторе, или используйте константы.