Определяем тип метаданных: от конфигуратора до ТипЗнч и Метаданные()
Содержание
Тип значения во время работы даёт функция ТипЗнч(Значение). Класс и имя объекта метаданных — метод Значение.Метаданные() и его ПолноеИмя(). А если нужно просто посмотреть глазами — откройте дерево конфигурации в конфигураторе: под каким узлом (Справочники, Документы, Регистры сведений) лежит объект, такой у него и тип.
Дальше разберём каждый способ с рабочим кодом: как сравнить тип ссылки с эталоном, как по ссылке понять, справочник это или документ, как достать список типов из ОписаниеТипов и в чём подвох у планов видов характеристик. Примеры рассчитаны на платформу 8.3 с интерфейсом «Такси».
Функция ТипЗнч — быстрый способ узнать тип значения
ТипЗнч() принимает любое значение и возвращает его тип — объект класса Тип. Сравнивать результат нужно не со строкой, а с результатом функции Тип("..."):
Если ТипЗнч(Значение) = Тип("СправочникСсылка.Контрагенты") Тогда
Сообщить("Это ссылка на контрагента");
КонецЕсли;
Обратите внимание на имя типа. У ссылки это СправочникСсылка.<Имя>, у объекта (например, в модуле документа при записи) — СправочникОбъект.<Имя>, у документа — ДокументСсылка.<Имя> и ДокументОбъект.<Имя>. Перепутаете Ссылка и Объект — проверка молча вернёт Ложь.
Для примитивов имена короткие: Тип("Строка"), Тип("Число"), Тип("Дата"), Тип("Булево"), Тип("Неопределено"). Проверка на пустое значение из запроса или реквизита:
Если ТипЗнч(Значение) = Тип("Неопределено") Тогда
Возврат;
КонецЕсли;
ТипЗнч() работает и с пустой ссылкой. Пустая ссылка справочника всё равно «знает» свой тип, поэтому ТипЗнч(Справочники.Контрагенты.ПустаяСсылка()) вернёт Тип("СправочникСсылка.Контрагенты").
Метод Метаданные(): имя и полное имя объекта
ТипЗнч() отвечает на вопрос «какого типа значение». А метод Метаданные() возвращает сам объект метаданных — с именем, синонимом, реквизитами и табличными частями:
МетаОбъекта = Ссылка.Метаданные();
Сообщить(МетаОбъекта.Имя); // Контрагенты
Сообщить(МетаОбъекта.ПолноеИмя()); // Справочник.Контрагенты
Сообщить(МетаОбъекта.Синоним); // Контрагенты (как в интерфейсе)
Разница между Имя и ПолноеИмя() важна:
Имя— короткое имя объекта без указания класса:Контрагенты.ПолноеИмя()— с префиксом класса через точку:Справочник.Контрагенты,Документ.РеализацияТоваровУслуг,РегистрСведений.ЦеныНоменклатуры.
Объект метаданных — это ещё и вход к структуре. У него есть коллекции Реквизиты, ТабличныеЧасти, СтандартныеРеквизиты, Формы. По ним удобно понять, из чего состоит объект, не открывая конфигуратор:
МД = Ссылка.Метаданные();
Сообщить("Реквизитов: " + Строка(МД.Реквизиты.Количество()));
Для Каждого ТЧ Из МД.ТабличныеЧасти Цикл
Сообщить("Табличная часть: " + ТЧ.Имя);
КонецЦикла;
Метод Метаданные() есть не только у ссылок. Его отдаёт и объект (СправочникОбъект, ДокументОбъект), и менеджер записи регистра, и выборка. А вот у числа или строки метода Метаданные() нет — вызов на примитиве приведёт к ошибке, поэтому тип стоит проверить заранее.
Как посмотреть тип в конфигураторе
Когда код писать не нужно, тип метаданных виден в дереве конфигурации.
- Откройте конфигуратор:
Конфигурация → Открыть конфигурацию. - В дереве объекты сгруппированы по классам:
Константы,Справочники,Документы,Планы видов характеристик,Регистры сведений,Регистры накопленияи так далее. Узел-родитель и есть тип метаданных. - Двойной клик по объекту открывает окно редактирования, клавиша
F2на выделенном объекте — палитру свойств.
Классов метаданных в дереве несколько десятков, но на практике чаще всего встречаются:
- Ссылочные —
Справочники,Документы,Планы счетов,Планы видов характеристик,Планы обмена,Задачи,Бизнес-процессы. У них есть ссылки, их значения можно хранить в реквизитах. - Регистры —
Регистры сведений,Регистры накопления,Регистры бухгалтерии,Регистры расчёта. Ссылок не имеют, данные адресуются по измерениям. - Прочие —
Константы,Перечисления,Обработки,Отчёты,Общие модули.
Класс объекта в дереве сразу подсказывает, как с ним работать в коде: у ссылочных есть ПустаяСсылка() и менеджер ТипВсеСсылки(), у регистров — наборы записей и выборки.
Чтобы узнать тип реквизита, разверните ветку Реквизиты у объекта и откройте нужный реквизит. В палитре свойств строка Тип показывает ОписаниеТипов. Нажмите кнопку с тремя точками справа — откроется редактор типа с галочками: примитивы, ссылочные типы, составной тип (несколько галочек сразу).
Полное имя выделенного объекта удобно скопировать прямо в дереве: контекстное меню содержит команду копирования имени, которую потом можно вставить в Тип("...") без опечаток.
Определяем класс объекта по ссылке
Частая задача: на входе ссылка неизвестного вида, нужно понять — справочник это, документ или план счетов
. Самый короткий путь — разобрать ПолноеИмя() по точке:
Функция КлассОбъекта(Знач Ссылка) Экспорт
ПолноеИмя = Ссылка.Метаданные().ПолноеИмя();
Возврат СтрРазделить(ПолноеИмя, ".")[0];
КонецФункции
Функция вернёт строку Справочник, Документ, ПланСчетов, ПланВидовХарактеристик, ПланОбмена, Задача или БизнесПроцесс — ровно те классы, у которых есть ссылки.
Второй способ — проверить принадлежность объекта к коллекции метаданных. У каждой коллекции (Метаданные.Справочники, Метаданные.Документы) есть метод Содержит():
МД = Ссылка.Метаданные();
Если Метаданные.Документы.Содержит(МД) Тогда
Сообщить("Документ");
ИначеЕсли Метаданные.Справочники.Содержит(МД) Тогда
Сообщить("Справочник");
КонецЕсли;
Третий способ пригодится, когда нужно не разбирать имя, а одним условием проверить «это любой справочник / любой документ». Менеджеры отдают описание всех ссылочных типов своего класса:
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
Сообщить("Значение — ссылка на какой-то справочник");
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
Сообщить("Значение — ссылка на какой-то документ");
КонецЕсли;
Справочники.ТипВсеСсылки() возвращает ОписаниеТипов, объединяющее ссылки на все справочники конфигурации, а метод СодержитТип() проверяет, входит ли туда конкретный тип. Аналогичный метод есть у менеджеров Документы, ПланыСчетов, ПланыВидовХарактеристик, Задачи и БизнесПроцессы — так можно одним условием распознать весь класс, не перечисляя объекты по одному.
Какой из трёх способов выбрать, зависит от задачи: разбор ПолноеИмя() даёт готовую строку класса, Содержит() удобен при проверке конкретного объекта, а ТипВсеСсылки() — когда нужна проверка «любой справочник / любой документ».
| Нужно узнать | Инструмент | Что вернёт |
|---|---|---|
| Тип конкретного значения | ТипЗнч(Значение) | объект Тип |
| Имя объекта метаданных | Ссылка.Метаданные().Имя | строка, напр. Контрагенты |
| Класс + имя | Ссылка.Метаданные().ПолноеИмя() | Справочник.Контрагенты |
| Класс объекта | СтрРазделить(ПолноеИмя, ".")[0] | Справочник |
| «Это любой справочник?» | Справочники.ТипВсеСсылки().СодержитТип(...) | Булево |
Коллекции типов: работаем с ОписаниеТипов
Если у реквизита или колонки несколько допустимых типов, они описаны объектом ОписаниеТипов. Он отвечает на два главных вопроса: какие типы разрешены и входит ли нужный тип в набор.
Описание = Новый ОписаниеТипов("СправочникСсылка.Контрагенты, Строка");
Если Описание.СодержитТип(Тип("Строка")) Тогда
Сообщить("В составном типе есть строка");
КонецЕсли;
Для Каждого ТекущийТип Из Описание.Типы() Цикл
// ТекущийТип — объект Тип, его можно сравнить через =
Если ТекущийТип = Тип("СправочникСсылка.Контрагенты") Тогда
Сообщить("Среди типов есть ссылка на контрагента");
КонецЕсли;
КонецЦикла;
Метод Типы() отдаёт массив объектов Тип — по нему удобно бежать циклом. Метод СодержитТип() короче, когда достаточно проверить один конкретный тип.
Описание типов хранится у многих объектов платформы:
- у реквизита метаданных — свойство
Тип(это и естьОписаниеТипов); - у колонки таблицы значений — свойство
ТипЗначения; - у реквизита формы и у параметра запроса — тоже
ОписаниеТипов.
У таблицы значений тип каждой колонки тоже лежит в ТипЗначения. Это помогает разобраться со структурой данных, пришедших из внешнего источника или сформированных запросом:
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
Описание = Колонка.ТипЗначения;
Если Описание.Типы().Количество() = 0 Тогда
Сообщить(Колонка.Имя + " — тип не ограничен (любой)");
Иначе
Сообщить(СтрШаблон("%1 — типов: %2",
Колонка.Имя, Описание.Типы().Количество()));
КонецЕсли;
КонецЦикла;
Пустой массив Типы() означает, что колонка принимает значение любого типа — такое бывает, когда колонку добавили без явного указания типа.
Перебрать типы всех реквизитов справочника можно прямо по метаданным:
Для Каждого Реквизит Из Метаданные.Справочники.Контрагенты.Реквизиты Цикл
Сообщить(СтрШаблон("%1 — типов: %2",
Реквизит.Имя, Реквизит.Тип.Типы().Количество()));
КонецЦикла;
Здесь СтрШаблон сам приводит число к строке — склеивать строку с числом через + нельзя, будет ошибка приведения.
Как увидеть тип значения при отладке
Во время отладки тип переменной показывает платформа — выдумывать код не нужно.
- Поставьте точку останова (клавиша
F9на строке) и запустите отладку. - Когда выполнение остановится, откройте окно
Табло(менюОтладка → Табло). Введите имя переменной — в колонкеТиппоявится её текущий тип. - Для разового вычисления используйте
Отладка → Вычислить выражение(Shift+F9): введитеТипЗнч(Переменная)и выполните — платформа покажет значение и тип результата.
Если нужно вывести тип в сообщениях по ходу работы без остановки, подойдёт Сообщить(СтрШаблон("%1", ТипЗнч(Значение))) — представление типа попадёт в окно сообщений.
Отладка внешних обработок требует включённой отладки в параметрах информационной базы, а подключение к работающему сеансу — прав на отладку. На рабочей базе это согласуют с администратором: отладка притормаживает сеанс.
Особенность планов видов характеристик
У планов видов характеристик тип значения не задан жёстко в метаданных — он свой у каждого элемента. Поэтому определять его нужно не по типу ссылки, а по стандартному реквизиту ТипЗначения.
ТипЗначения — это ОписаниеТипов, которое хранится прямо в элементе плана видов характеристик и говорит, значения каких типов допустимы для данной характеристики (субконто, свойства, показателя):
ОписаниеТ = ВидХарактеристикиСсылка.ТипЗначения;
Если ОписаниеТ.СодержитТип(Тип("Число")) Тогда
Сообщить("Характеристика числовая");
ИначеЕсли ОписаниеТ.СодержитТип(Тип("Дата")) Тогда
Сообщить("Характеристика — дата");
КонецЕсли;
Набор типов, из которого вообще можно выбирать при настройке вида характеристики, задаётся в метаданных плана — свойство Тип значения характеристик. А конкретный тип отдельной характеристики лежит в её реквизите ТипЗначения. Не путайте эти два уровня: метаданные задают рамку допустимых типов, элемент — фактический тип своего значения.
Определение типа в языке запросов
Тип значения можно выяснить и прямо в запросе — особенно когда поле составное: субконто регистра бухгалтерии, значение характеристики, реквизит с несколькими типами. Для этого есть функции ТИПЗНАЧЕНИЯ() и ТИП().
ТИПЗНАЧЕНИЯ(Поле) возвращает тип значения в этом поле строки. Сравнивают его с ТИП(...), где имя пишется без суффикса Ссылка:
ВЫБРАТЬ
Движения.Субконто1 КАК Субконто,
ТИПЗНАЧЕНИЯ(Движения.Субконто1) КАК ТипСубконто
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты КАК Движения
ГДЕ
ТИПЗНАЧЕНИЯ(Движения.Субконто1) = ТИП(Справочник.Контрагенты)
Когда поле составного типа нужно привести к конкретному, применяют ВЫРАЗИТЬ(... КАК ...). Это позволяет обратиться к реквизитам приведённого типа:
ВЫБРАТЬ
ВЫРАЗИТЬ(Таблица.Субконто1 КАК Справочник.Контрагенты).ИНН КАК ИНН
ИЗ
...
Если тип поля заранее неизвестен, сначала отберите нужные строки по ТИПЗНАЧЕНИЯ(...) = ТИП(...), а уже потом применяйте ВЫРАЗИТЬ — иначе для строк другого типа реквизит вернёт NULL.
Типичные ошибки при определении типа
- 🔴 Сравнение со строкой вместо
Тип(). ЗаписьТипЗнч(Значение) = "СправочникСсылка.Контрагенты"всегда даётЛожь: слева объектТип, справа строка. НужноТип("СправочникСсылка.Контрагенты"). - 🔴 Путаница
СсылкаиОбъект. В обработке проведения или в модуле объекта значение имеет тип...Объект.<Имя>, а не...Ссылка.<Имя>. Проверка на ссылочный тип там не сработает. - 🔴 Вызов
Метаданные()на примитиве. У числа, строки, булева нет методаМетаданные(). Сначала убедитесь, что значение ссылочное — например, черезТипВсеСсылки().СодержитТип(...). - 🔴 Опечатка в имени типа.
Тип("Справочник.Контрагенты")— ошибка: у ссылки класс пишется какСправочникСсылка. А несуществующее имя вТип("...")вызовет исключение во время выполнения. - 🔴 Склейка числа со строкой.
"Типов: " + Количествопадает на приведении. ИспользуйтеСтрШаблонилиСтрока(Количество).
Частые вопросы
Чем `ТипЗнч()` отличается от `Метаданные()`?
ТипЗнч() возвращает тип значения (объект Тип) и работает с любыми данными, включая примитивы. Метаданные() возвращает объект метаданных с именем, реквизитами и табличными частями, но доступен только у объектов конфигурации — у числа или строки его нет.Как получить строковое имя типа ссылки?
Ссылка.Метаданные().ПолноеИмя() даст Справочник.Контрагенты, а Ссылка.Метаданные().Имя — короткое Контрагенты. Это надёжнее, чем преобразовывать сам объект Тип в строку.Как проверить, что значение — ссылка на любой справочник, не перечисляя все?
Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)). Метод ТипВсеСсылки() есть у менеджеров Справочники, Документы, ПланыСчетов и других ссылочных объектов.Почему у пустой ссылки всё равно есть тип?
ТипЗнч(ПустаяСсылка) вернёт нормальный ссылочный тип, а .Метаданные() на ней отработает корректно.Как узнать тип значения конкретной характеристики в плане видов характеристик?
ТипЗначения элемента — это ОписаниеТипов. Проверяйте вхождение нужного типа методом СодержитТип().