ВЫРАЗИТЬ и определяемые типы: как отбирать и разыменовывать составные поля в запросе

· 9 мин

Содержание

Выразить поле напрямую как определяемый тип в запросе 1С нельзя: язык запросов не знает объекта ОпределяемыйТип, и конструкция ВЫРАЗИТЬ(Поле КАК ОпределяемыйТип.Владелец) даёт синтаксическую ошибку. Рабочих способов три: привести поле к каждому конкретному типу из состава через ВЫРАЗИТЬ, отобрать записи оператором ССЫЛКА или собрать текст запроса программно из Метаданные.ОпределяемыеТипы.

Первый способ годится, когда состав определяемого типа короткий и стабильный. Второй — для отбора без разыменования. Третий нужен, когда состав меняется от релиза к релизу или дополняется при внедрении: код не придётся править после каждого обновления.

Всё ниже относится к платформе 1С:Предприятие 8.3 и не зависит от конкретной конфигурации: БП, ЗУП, УТ или своя разработка — механизм одинаковый.

Что такое определяемый тип и как его видит запрос

Определяемый тип — объект метаданных в ветке Общие → Определяемые типы. В нём хранится только описание типов: список ссылок и, при необходимости, примитивов. Потом этот «набор» назначают типом реквизитам, измерениям и ресурсам вместо того, чтобы перечислять типы в каждом поле вручную.

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

  • 🔹 в составе один тип — поле ведёт себя как обычная ссылка, ВЫРАЗИТЬ не нужен;
  • 🔹 в составе несколько типов — поле составное, со всеми последствиями для запросов;
  • 🔹 в составе есть примитивы (Строка, Число) — поле может хранить и ссылку, и значение.

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

Посмотреть состав быстро можно в Конфигураторе: откройте определяемый тип, вкладка «Основные», поле «Тип». Там же видно, отмечен ли флажок «Составной тип данных».

Синтаксис: ВЫРАЗИТЬ, ССЫЛКА и ТИПЗНАЧЕНИЯ для поля определяемого типа

Для составного поля в языке запросов 1С есть три инструмента. Все они работают с конкретными типами, а не с определяемым типом целиком.

КонструкцияЧто делаетКогда применять
ВЫРАЗИТЬ(Поле КАК Справочник.Контрагенты)Приводит поле к одному типу. Если значение другого типа — вернёт NULLНужно обратиться к реквизитам через точку
Поле ССЫЛКА Справочник.КонтрагентыЛогическое условие: значение принадлежит таблицеОтбор в ГДЕ, ветки ВЫБОР
ТИПЗНАЧЕНИЯ(Поле) = ТИП(Справочник.Контрагенты)Сравнивает тип значения с заданнымТо же, что ССЫЛКА, плюс примитивы: ТИП(СТРОКА)

Для примитивов внутри составного поля приведение пишется с параметрами типа:

ВЫРАЗИТЬ(Т.Значение КАК СТРОКА(150))
ВЫРАЗИТЬ(Т.Значение КАК ЧИСЛО(15, 2))

Строку неограниченной длины без ВЫРАЗИТЬ нельзя сравнивать и группировать — для составных полей с типом Строка это частая ловушка.

Чего в синтаксисе нет совсем:

  • ❌ ВЫРАЗИТЬ(Поле КАК ОпределяемыйТип.Имя);
  • ❌ ТИП(ОпределяемыйТип.Имя);
  • ❌ параметр запроса типа ОписаниеТипов, который сам «развернётся» в условие.

Примеры запросов с определяемым типом

Дальше в примерах — условный регистр сведений КонтактыВладельцев. Его измерение Владелец имеет тип определяемого типа ВладелецКонтакта, в составе которого Справочник.Контрагенты, Справочник.Организации и Справочник.ФизическиеЛица. Имена учебные: подставьте свои.

Пример 1. Отбор записей только по одному типу из состава

ВЫБРАТЬ
	К.Владелец,
	К.Телефон
ИЗ
	РегистрСведений.КонтактыВладельцев КАК К
ГДЕ
	К.Владелец ССЫЛКА Справочник.Контрагенты

Разыменования нет, поэтому лишних соединений не будет. Это самый дешёвый вариант отбора.

Пример 2. Реквизит, который есть у нескольких типов

У контрагентов и организаций есть ИНН, у физлиц он тоже есть, но в другом справочнике может отсутствовать. Каждую ветку выражаем отдельно:

ВЫБРАТЬ
	К.Владелец,
	ВЫБОР
		КОГДА К.Владелец ССЫЛКА Справочник.Контрагенты
			ТОГДА ВЫРАЗИТЬ(К.Владелец КАК Справочник.Контрагенты).ИНН
		КОГДА К.Владелец ССЫЛКА Справочник.Организации
			ТОГДА ВЫРАЗИТЬ(К.Владелец КАК Справочник.Организации).ИНН
		ИНАЧЕ ""
	КОНЕЦ КАК ИНН
ИЗ
	РегистрСведений.КонтактыВладельцев КАК К

Ветка ИНАЧЕ обязательна по смыслу: без неё для физлиц и пустых значений придёт NULL.

Пример 3. Условие, собранное из метаданных

Когда состав определяемого типа может измениться, условие собирают на сервере. Функция ниже возвращает текст вида (К.Владелец ССЫЛКА Справочник.Контрагенты ИЛИ ...):

&НаСервере
Функция УсловиеПоОпределяемомуТипу(ИмяПоля, ИмяОпределяемогоТипа)

	ОбъектМД = Метаданные.ОпределяемыеТипы.Найти(ИмяОпределяемогоТипа);
	Если ОбъектМД = Неопределено Тогда
		ВызватьИсключение СтрШаблон("Нет определяемого типа %1", ИмяОпределяемогоТипа);
	КонецЕсли;

	Части = Новый Массив;
	Для Каждого ТекущийТип Из ОбъектМД.Тип.Типы() Цикл
		МетаданныеТипа = Метаданные.НайтиПоТипу(ТекущийТип);
		Если МетаданныеТипа = Неопределено Тогда
			Продолжить; // примитивный тип: Строка, Число и т.п.
		КонецЕсли;
		Части.Добавить(СтрШаблон("%1 ССЫЛКА %2", ИмяПоля, МетаданныеТипа.ПолноеИмя()));
	КонецЦикла;

	Если Части.Количество() = 0 Тогда
		Возврат "ЛОЖЬ";
	КонецЕсли;

	Возврат "(" + СтрСоединить(Части, " ИЛИ ") + ")";

КонецФункции

Применение — через метку в тексте запроса:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	К.Владелец,
|	К.Телефон
|ИЗ
|	РегистрСведений.КонтактыВладельцев КАК К
|ГДЕ
|	&УсловиеПоВладельцу";

Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеПоВладельцу",
	УсловиеПоОпределяемомуТипу("К.Владелец", "ВладелецКонтакта"));

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

СтрСоединить и СтрШаблон есть в платформе с версии 8.3.6. Для более старых режимов совместимости соберите строку обычной конкатенацией в цикле.

Пример 4. Ветки ВЫБОР по всему составу

Тот же приём строит и разыменование. В цикле по Тип.Типы() формируются строки КОГДА ... ССЫЛКА ... ТОГДА ВЫРАЗИТЬ(... КАК ...).Наименование, а затем вставляются между ВЫБОР и ИНАЧЕ "" КОНЕЦ. Условие одно: нужный реквизит должен быть у каждой таблицы из состава. Проверить это можно в том же цикле через МетаданныеТипа.Реквизиты.Найти("ИНН") — стандартные реквизиты вроде Наименование в эту коллекцию не входят, их проверяют иначе или просто знают по виду объекта.

Ошибки при работе с определяемым типом в запросе

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

Ещё три промаха, которые не выдают ошибку, но портят результат:

  1. Пустое значение составного поля. Незаполненное составное поле хранит НЕОПРЕДЕЛЕНО, а не пустую ссылку конкретного справочника. Условие = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) такие записи не поймает. Проверяйте оба варианта.
  2. Вызов метаданных на клиенте. Сборку условия держите в серверной процедуре: запрос всё равно выполняется на сервере, а лишние серверные вызовы из клиента замедляют форму.
  3. Подстановка имени через параметр. Имя таблицы нельзя передать в &Параметр — только вставить в текст. Вставляйте только имена из метаданных, никогда не берите их из ввода пользователя.

Как ускорить запрос с полем определяемого типа

Главная проблема — неявные соединения. Когда пишут К.Владелец.Наименование, а в составе определяемого типа десять справочников, платформа строит соединение с каждым из десяти. В отчёте на сотни тысяч строк это заметно.

Что помогает:

  • ✅ ВЫРАЗИТЬ перед точкой. ВЫРАЗИТЬ(К.Владелец КАК Справочник.Контрагенты).ИНН соединяет одну таблицу вместо всех.
  • ✅ Сначала отбор, потом разыменование. Отберите записи нужного типа во временную таблицу через ССЫЛКА, а реквизиты получайте уже из неё.
  • ✅ ПРЕДСТАВЛЕНИЕССЫЛКИ вместо ПРЕДСТАВЛЕНИЕ для вывода ссылок. Для составного поля обе дают соединения с таблицами состава, поэтому выводите представление только там, где оно действительно нужно, а для отбора используйте саму ссылку.
  • ✅ Отбор по типу дешевле отбора по реквизиту. ССЫЛКА и ТИПЗНАЧЕНИЯ проверяют поле типа, который хранится в той же строке таблицы, без обращения к другим таблицам.

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

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

Проверьте себя
В составе определяемого типа один справочник. Нужен ли ВЫРАЗИТЬ перед точкой?
Что вернёт ВЫРАЗИТЬ(Поле КАК Справочник.Контрагенты), если в поле организация?
Можно ли передать имя таблицы для ССЫЛКА через параметр запроса?

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

Определяемые типы появились в платформе 8.3.3. В 8.2 их нет: там составной тип перечисляют прямо в реквизите, а в запросах работают те же ВЫРАЗИТЬ и ССЫЛКА. Синтаксис языка запросов для составных полей с тех пор не менялся.

Что зависит от версии на практике:

ЧтоС какой версии платформыВлияние на код
Объект «Определяемый тип»8.3.3Состав типа можно читать из Метаданные.ОпределяемыеТипы
Расширения конфигурации8.3.6Типовая конфигурация может получать доработки без снятия с поддержки
СтрСоединить, СтрШаблон8.3.6Удобная сборка текста условия

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

В типовых конфигурациях на базе БСП определяемыми типами описаны, например, владельцы файлов и объекты с дополнительными сведениями. Их состав заполняется при внедрении подсистем и растёт при обновлениях. Поэтому ручной список типов в запросе к таким данным устаревает быстрее всего.

Когда лучше обойтись без определяемого типа

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

Что нужно хранить в поле?

Ещё один вариант для отчётов — хранить нужный реквизит прямо в регистре. Например, отдельный ресурс ИНН рядом с составным Владелец. Это дублирование данных, зато отчёт обходится без соединений вовсе. Решение оправдано, когда отчёт тяжёлый и запускается часто.

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

Можно ли получить список типов определяемого типа прямо в запросе?
Нет. Язык запросов не обращается к метаданным. Состав читают во встроенном языке: Метаданные.ОпределяемыеТипы.Имя.Тип.Типы().
Работает ли ВЫРАЗИТЬ в запросе системы компоновки данных?
Да, текст набора данных СКД — обычный язык запросов. Все приёмы с ВЫРАЗИТЬ, ССЫЛКА и ТИПЗНАЧЕНИЯ в нём действуют.
Как отобрать записи, где поле определяемого типа не заполнено?
Используйте условие К.Владелец = НЕОПРЕДЕЛЕНО. Если поле могли заполнить пустой ссылкой программно, добавьте проверку пустых ссылок нужных справочников.
Можно ли выразить поле к нескольким типам одной конструкцией?
Нет. Одна ВЫРАЗИТЬ приводит к одному типу. Для нескольких используйте ВЫБОР с ветками или объединение запросов по типам.