ВЫРАЗИТЬ и определяемые типы: как отбирать и разыменовывать составные поля в запросе
Содержание
Выразить поле напрямую как определяемый тип в запросе 1С нельзя: язык запросов не знает объекта ОпределяемыйТип, и конструкция ВЫРАЗИТЬ(Поле КАК ОпределяемыйТип.Владелец) даёт синтаксическую ошибку. Рабочих способов три: привести поле к каждому конкретному типу из состава через ВЫРАЗИТЬ, отобрать записи оператором ССЫЛКА или собрать текст запроса программно из Метаданные.ОпределяемыеТипы.
Первый способ годится, когда состав определяемого типа короткий и стабильный. Второй — для отбора без разыменования. Третий нужен, когда состав меняется от релиза к релизу или дополняется при внедрении: код не придётся править после каждого обновления.
Всё ниже относится к платформе 1С:Предприятие 8.3 и не зависит от конкретной конфигурации: БП, ЗУП, УТ или своя разработка — механизм одинаковый.
Что такое определяемый тип и как его видит запрос
Определяемый тип — объект метаданных в ветке Общие → Определяемые типы. В нём хранится только описание типов: список ссылок и, при необходимости, примитивов. Потом этот «набор» назначают типом реквизитам, измерениям и ресурсам вместо того, чтобы перечислять типы в каждом поле вручную.
Главное для запросов: определяемый тип существует только на уровне конфигурации. В базе данных и в языке запросов его нет. Платформа разворачивает его в обычный тип:
- 🔹 в составе один тип — поле ведёт себя как обычная ссылка,
ВЫРАЗИТЬне нужен; - 🔹 в составе несколько типов — поле составное, со всеми последствиями для запросов;
- 🔹 в составе есть примитивы (
Строка,Число) — поле может хранить и ссылку, и значение.
Отсюда простое правило. Запрос работает не с определяемым типом, а с конкретными таблицами из его состава. Всё, что нужно сделать, — перечислить эти таблицы явно или сформировать список программно.
Посмотреть состав быстро можно в Конфигураторе: откройте определяемый тип, вкладка «Основные», поле «Тип». Там же видно, отмечен ли флажок «Составной тип данных».
Синтаксис: ВЫРАЗИТЬ, ССЫЛКА и ТИПЗНАЧЕНИЯ для поля определяемого типа
Для составного поля в языке запросов 1С есть три инструмента. Все они работают с конкретными типами, а не с определяемым типом целиком.
| Конструкция | Что делает | Когда применять |
|---|---|---|
ВЫРАЗИТЬ(Поле КАК Справочник.Контрагенты) | Приводит поле к одному типу. Если значение другого типа — вернёт NULL | Нужно обратиться к реквизитам через точку |
Поле ССЫЛКА Справочник.Контрагенты | Логическое условие: значение принадлежит таблице | Отбор в ГДЕ, ветки ВЫБОР |
ТИПЗНАЧЕНИЯ(Поле) = ТИП(Справочник.Контрагенты) | Сравнивает тип значения с заданным | То же, что ССЫЛКА, плюс примитивы: ТИП(СТРОКА) |
Для примитивов внутри составного поля приведение пишется с параметрами типа:
ВЫРАЗИТЬ(Т.Значение КАК СТРОКА(150))
ВЫРАЗИТЬ(Т.Значение КАК ЧИСЛО(15, 2))
Строку неограниченной длины без ВЫРАЗИТЬ нельзя сравнивать и группировать — для составных полей с типом Строка это частая ловушка.
Чего в синтаксисе нет совсем:
- ❌
ВЫРАЗИТЬ(Поле КАК ОпределяемыйТип.Имя); - ❌
ТИП(ОпределяемыйТип.Имя); - ❌ параметр запроса типа
ОписаниеТипов, который сам «развернётся» в условие.
Примеры запросов с определяемым типом
Дальше в примерах — условный регистр сведений
КонтактыВладельцев. Его измерение Владелец имеет тип определяемого типа ВладелецКонтакта, в составе которого Справочник.Контрагенты, Справочник.Организации и Справочник.ФизическиеЛица. Имена учебные: подставьте свои.
Пример 1. Отбор записей только по одному типу из состава
ВЫБРАТЬ
К.Владелец,
К.Телефон
ИЗ
РегистрСведений.КонтактыВладельцев КАК К
ГДЕ
К.Владелец ССЫЛКА Справочник.Контрагенты
Разыменования нет, поэтому лишних соединений не будет. Это самый дешёвый вариант отбора.
Пример 2. Реквизит, который есть у нескольких типов
У контрагентов и организаций есть ИНН, у физлиц он тоже есть, но в другом справочнике может отсутствовать. Каждую ветку выражаем отдельно:
ВЫБРАТЬ
К.Владелец,
ВЫБОР
КОГДА К.Владелец ССЫЛКА Справочник.Контрагенты
ТОГДА ВЫРАЗИТЬ(К.Владелец КАК Справочник.Контрагенты).ИНН
КОГДА К.Владелец ССЫЛКА Справочник.Организации
ТОГДА ВЫРАЗИТЬ(К.Владелец КАК Справочник.Организации).ИНН
ИНАЧЕ ""
КОНЕЦ КАК ИНН
ИЗ
РегистрСведений.КонтактыВладельцев КАК К
Ветка ИНАЧЕ обязательна по смыслу: без неё для физлиц и пустых значений придёт NULL.
Пример 3. Условие, собранное из метаданных
Когда состав определяемого типа может измениться, условие собирают на сервере. Функция ниже возвращает текст вида (К.Владелец ССЫЛКА Справочник.Контрагенты ИЛИ ...):
&НаСервере
Функция УсловиеПоОпределяемомуТипу(ИмяПоля, ИмяОпределяемогоТипа)
ОбъектМД = Метаданные.ОпределяемыеТипы.Найти(ИмяОпределяемогоТипа);
Если ОбъектМД = Неопределено Тогда
ВызватьИсключение СтрШаблон("Нет определяемого типа %1", ИмяОпределяемогоТипа);
КонецЕсли;
Части = Новый Массив;
Для Каждого ТекущийТип Из ОбъектМД.Тип.Типы() Цикл
МетаданныеТипа = Метаданные.НайтиПоТипу(ТекущийТип);
Если МетаданныеТипа = Неопределено Тогда
Продолжить; // примитивный тип: Строка, Число и т.п.
КонецЕсли;
Части.Добавить(СтрШаблон("%1 ССЫЛКА %2", ИмяПоля, МетаданныеТипа.ПолноеИмя()));
КонецЦикла;
Если Части.Количество() = 0 Тогда
Возврат "ЛОЖЬ";
КонецЕсли;
Возврат "(" + СтрСоединить(Части, " ИЛИ ") + ")";
КонецФункции
Применение — через метку в тексте запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| К.Владелец,
| К.Телефон
|ИЗ
| РегистрСведений.КонтактыВладельцев КАК К
|ГДЕ
| &УсловиеПоВладельцу";
Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеПоВладельцу",
УсловиеПоОпределяемомуТипу("К.Владелец", "ВладелецКонтакта"));
Результат = Запрос.Выполнить().Выгрузить();
СтрСоединить и СтрШаблон есть в платформе с версии 8.3.6. Для более старых режимов совместимости соберите строку обычной конкатенацией в цикле.
Пример 4. Ветки ВЫБОР по всему составу
Тот же приём строит и разыменование. В цикле по Тип.Типы() формируются строки КОГДА ... ССЫЛКА ... ТОГДА ВЫРАЗИТЬ(... КАК ...).Наименование, а затем вставляются между ВЫБОР и ИНАЧЕ "" КОНЕЦ. Условие одно: нужный реквизит должен быть у каждой таблицы из состава. Проверить это можно в том же цикле через МетаданныеТипа.Реквизиты.Найти("ИНН") — стандартные реквизиты вроде Наименование в эту коллекцию не входят, их проверяют иначе или просто знают по виду объекта.
Ошибки при работе с определяемым типом в запросе
Ещё три промаха, которые не выдают ошибку, но портят результат:
- Пустое значение составного поля. Незаполненное составное поле хранит
НЕОПРЕДЕЛЕНО, а не пустую ссылку конкретного справочника. Условие= ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)такие записи не поймает. Проверяйте оба варианта. - Вызов метаданных на клиенте. Сборку условия держите в серверной процедуре: запрос всё равно выполняется на сервере, а лишние серверные вызовы из клиента замедляют форму.
- Подстановка имени через параметр. Имя таблицы нельзя передать в
&Параметр— только вставить в текст. Вставляйте только имена из метаданных, никогда не берите их из ввода пользователя.
Как ускорить запрос с полем определяемого типа
Главная проблема — неявные соединения. Когда пишут К.Владелец.Наименование, а в составе определяемого типа десять справочников, платформа строит соединение с каждым из десяти. В отчёте на сотни тысяч строк это заметно.
Что помогает:
- ✅
ВЫРАЗИТЬперед точкой.ВЫРАЗИТЬ(К.Владелец КАК Справочник.Контрагенты).ИННсоединяет одну таблицу вместо всех. - ✅ Сначала отбор, потом разыменование. Отберите записи нужного типа во временную таблицу через
ССЫЛКА, а реквизиты получайте уже из неё. - ✅
ПРЕДСТАВЛЕНИЕССЫЛКИвместоПРЕДСТАВЛЕНИЕдля вывода ссылок. Для составного поля обе дают соединения с таблицами состава, поэтому выводите представление только там, где оно действительно нужно, а для отбора используйте саму ссылку. - ✅ Отбор по типу дешевле отбора по реквизиту.
ССЫЛКАиТИПЗНАЧЕНИЯпроверяют поле типа, который хранится в той же строке таблицы, без обращения к другим таблицам.
В системе компоновки данных пользователь может сам вывести в отчёт Владелец.ИНН через настройки. Если отчёт тормозит, посмотрите не только текст запроса, но и выбранные поля в варианте отчёта.
Проверять эффект удобно замером производительности в режиме отладки или технологическим журналом на клиент-серверной базе. Сравнивайте время запроса до и после правки на одной и той же выборке.
Определяемые типы в разных версиях платформы
Определяемые типы появились в платформе 8.3.3. В 8.2 их нет: там составной тип перечисляют прямо в реквизите, а в запросах работают те же ВЫРАЗИТЬ и ССЫЛКА. Синтаксис языка запросов для составных полей с тех пор не менялся.
Что зависит от версии на практике:
| Что | С какой версии платформы | Влияние на код |
|---|---|---|
| Объект «Определяемый тип» | 8.3.3 | Состав типа можно читать из Метаданные.ОпределяемыеТипы |
| Расширения конфигурации | 8.3.6 | Типовая конфигурация может получать доработки без снятия с поддержки |
СтрСоединить, СтрШаблон | 8.3.6 | Удобная сборка текста условия |
Режим совместимости тоже важен. Если конфигурация работает в режиме совместимости ниже версии, где появилась функция, вызов этой функции не пройдёт синтаксический контроль. Проверьте свойство РежимСовместимости в корне конфигурации перед тем, как использовать новые функции.
В типовых конфигурациях на базе БСП определяемыми типами описаны, например, владельцы файлов и объекты с дополнительными сведениями. Их состав заполняется при внедрении подсистем и растёт при обновлениях. Поэтому ручной список типов в запросе к таким данным устаревает быстрее всего.
Когда лучше обойтись без определяемого типа
Определяемый тип удобен для разработчика, но в запросах он всегда превращается в составное поле. Иногда проще другая модель данных.
Ещё один вариант для отчётов — хранить нужный реквизит прямо в регистре. Например, отдельный ресурс ИНН рядом с составным Владелец. Это дублирование данных, зато отчёт обходится без соединений вовсе. Решение оправдано, когда отчёт тяжёлый и запускается часто.
Частые вопросы
Можно ли получить список типов определяемого типа прямо в запросе?
Метаданные.ОпределяемыеТипы.Имя.Тип.Типы().Работает ли ВЫРАЗИТЬ в запросе системы компоновки данных?
ВЫРАЗИТЬ, ССЫЛКА и ТИПЗНАЧЕНИЯ в нём действуют.Как отобрать записи, где поле определяемого типа не заполнено?
К.Владелец = НЕОПРЕДЕЛЕНО. Если поле могли заполнить пустой ссылкой программно, добавьте проверку пустых ссылок нужных справочников.Можно ли выразить поле к нескольким типам одной конструкцией?
ВЫРАЗИТЬ приводит к одному типу. Для нескольких используйте ВЫБОР с ветками или объединение запросов по типам.