Определяем тип метаданных: от конфигуратора до ТипЗнч и Метаданные()

· 9 мин

Содержание

Тип значения во время работы даёт функция ТипЗнч(Значение). Класс и имя объекта метаданных — метод Значение.Метаданные() и его ПолноеИмя(). А если нужно просто посмотреть глазами — откройте дерево конфигурации в конфигураторе: под каким узлом (Справочники, Документы, Регистры сведений) лежит объект, такой у него и тип.

Дальше разберём каждый способ с рабочим кодом: как сравнить тип ссылки с эталоном, как по ссылке понять, справочник это или документ, как достать список типов из ОписаниеТипов и в чём подвох у планов видов характеристик. Примеры рассчитаны на платформу 8.3 с интерфейсом «Такси».

Функция ТипЗнч — быстрый способ узнать тип значения

ТипЗнч() принимает любое значение и возвращает его тип — объект класса Тип. Сравнивать результат нужно не со строкой, а с результатом функции Тип("..."):

Если ТипЗнч(Значение) = Тип("СправочникСсылка.Контрагенты") Тогда
    Сообщить("Это ссылка на контрагента");
КонецЕсли;

Обратите внимание на имя типа. У ссылки это СправочникСсылка.<Имя>, у объекта (например, в модуле документа при записи) — СправочникОбъект.<Имя>, у документа — ДокументСсылка.<Имя> и ДокументОбъект.<Имя>. Перепутаете Ссылка и Объект — проверка молча вернёт Ложь.

Для примитивов имена короткие: Тип("Строка"), Тип("Число"), Тип("Дата"), Тип("Булево"), Тип("Неопределено"). Проверка на пустое значение из запроса или реквизита:

Если ТипЗнч(Значение) = Тип("Неопределено") Тогда
    Возврат;
КонецЕсли;

ТипЗнч() работает и с пустой ссылкой. Пустая ссылка справочника всё равно «знает» свой тип, поэтому ТипЗнч(Справочники.Контрагенты.ПустаяСсылка()) вернёт Тип("СправочникСсылка.Контрагенты").

Метод Метаданные(): имя и полное имя объекта

ТипЗнч() отвечает на вопрос «какого типа значение». А метод Метаданные() возвращает сам объект метаданных — с именем, синонимом, реквизитами и табличными частями:

МетаОбъекта = Ссылка.Метаданные();
Сообщить(МетаОбъекта.Имя);          // Контрагенты
Сообщить(МетаОбъекта.ПолноеИмя());  // Справочник.Контрагенты
Сообщить(МетаОбъекта.Синоним);      // Контрагенты (как в интерфейсе)

Разница между Имя и ПолноеИмя() важна:

  • Имя — короткое имя объекта без указания класса: Контрагенты.
  • ПолноеИмя() — с префиксом класса через точку: Справочник.Контрагенты, Документ.РеализацияТоваровУслуг, РегистрСведений.ЦеныНоменклатуры.

Объект метаданных — это ещё и вход к структуре. У него есть коллекции Реквизиты, ТабличныеЧасти, СтандартныеРеквизиты, Формы. По ним удобно понять, из чего состоит объект, не открывая конфигуратор:

МД = Ссылка.Метаданные();
Сообщить("Реквизитов: " + Строка(МД.Реквизиты.Количество()));
Для Каждого ТЧ Из МД.ТабличныеЧасти Цикл
    Сообщить("Табличная часть: " + ТЧ.Имя);
КонецЦикла;

Метод Метаданные() есть не только у ссылок. Его отдаёт и объект (СправочникОбъект, ДокументОбъект), и менеджер записи регистра, и выборка. А вот у числа или строки метода Метаданные() нет — вызов на примитиве приведёт к ошибке, поэтому тип стоит проверить заранее.

Как посмотреть тип в конфигураторе

Когда код писать не нужно, тип метаданных виден в дереве конфигурации.

  1. Откройте конфигуратор: Конфигурация → Открыть конфигурацию.
  2. В дереве объекты сгруппированы по классам: Константы, Справочники, Документы, Планы видов характеристик, Регистры сведений, Регистры накопления и так далее. Узел-родитель и есть тип метаданных.
  3. Двойной клик по объекту открывает окно редактирования, клавиша F2 на выделенном объекте — палитру свойств.

Классов метаданных в дереве несколько десятков, но на практике чаще всего встречаются:

  • Ссылочные — Справочники, Документы, Планы счетов, Планы видов характеристик, Планы обмена, Задачи, Бизнес-процессы. У них есть ссылки, их значения можно хранить в реквизитах.
  • Регистры — Регистры сведений, Регистры накопления, Регистры бухгалтерии, Регистры расчёта. Ссылок не имеют, данные адресуются по измерениям.
  • Прочие — Константы, Перечисления, Обработки, Отчёты, Общие модули.

Класс объекта в дереве сразу подсказывает, как с ним работать в коде: у ссылочных есть ПустаяСсылка() и менеджер ТипВсеСсылки(), у регистров — наборы записей и выборки.

Чтобы узнать тип реквизита, разверните ветку Реквизиты у объекта и откройте нужный реквизит. В палитре свойств строка Тип показывает ОписаниеТипов. Нажмите кнопку с тремя точками справа — откроется редактор типа с галочками: примитивы, ссылочные типы, составной тип (несколько галочек сразу).

Полное имя выделенного объекта удобно скопировать прямо в дереве: контекстное меню содержит команду копирования имени, которую потом можно вставить в Тип("...") без опечаток.

Определяем класс объекта по ссылке

Частая задача: на входе ссылка неизвестного вида, нужно понять — справочник это, документ или план счетов . Самый короткий путь — разобрать ПолноеИмя() по точке:

Функция КлассОбъекта(Знач Ссылка) Экспорт
    ПолноеИмя = Ссылка.Метаданные().ПолноеИмя();
    Возврат СтрРазделить(ПолноеИмя, ".")[0];
КонецФункции

Функция вернёт строку Справочник, Документ, ПланСчетов, ПланВидовХарактеристик, ПланОбмена, Задача или БизнесПроцесс — ровно те классы, у которых есть ссылки.

Второй способ — проверить принадлежность объекта к коллекции метаданных. У каждой коллекции (Метаданные.Справочники, Метаданные.Документы) есть метод Содержит():

МД = Ссылка.Метаданные();
Если Метаданные.Документы.Содержит(МД) Тогда
    Сообщить("Документ");
ИначеЕсли Метаданные.Справочники.Содержит(МД) Тогда
    Сообщить("Справочник");
КонецЕсли;

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

Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
    Сообщить("Значение — ссылка на какой-то справочник");
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
    Сообщить("Значение — ссылка на какой-то документ");
КонецЕсли;

Справочники.ТипВсеСсылки() возвращает ОписаниеТипов, объединяющее ссылки на все справочники конфигурации, а метод СодержитТип() проверяет, входит ли туда конкретный тип. Аналогичный метод есть у менеджеров Документы, ПланыСчетов, ПланыВидовХарактеристик, Задачи и БизнесПроцессы — так можно одним условием распознать весь класс, не перечисляя объекты по одному.

Какой из трёх способов выбрать, зависит от задачи: разбор ПолноеИмя() даёт готовую строку класса, Содержит() удобен при проверке конкретного объекта, а ТипВсеСсылки() — когда нужна проверка «любой справочник / любой документ».

Нужно узнатьИнструментЧто вернёт
Тип конкретного значенияТипЗнч(Значение)объект Тип
Имя объекта метаданныхСсылка.Метаданные().Имястрока, напр. Контрагенты
Класс + имяСсылка.Метаданные().ПолноеИмя()Справочник.Контрагенты
Класс объектаСтрРазделить(ПолноеИмя, ".")[0]Справочник
«Это любой справочник?»Справочники.ТипВсеСсылки().СодержитТип(...)Булево

Коллекции типов: работаем с ОписаниеТипов

Если у реквизита или колонки несколько допустимых типов, они описаны объектом ОписаниеТипов. Он отвечает на два главных вопроса: какие типы разрешены и входит ли нужный тип в набор.

Описание = Новый ОписаниеТипов("СправочникСсылка.Контрагенты, Строка");

Если Описание.СодержитТип(Тип("Строка")) Тогда
    Сообщить("В составном типе есть строка");
КонецЕсли;

Для Каждого ТекущийТип Из Описание.Типы() Цикл
    // ТекущийТип — объект Тип, его можно сравнить через =
    Если ТекущийТип = Тип("СправочникСсылка.Контрагенты") Тогда
        Сообщить("Среди типов есть ссылка на контрагента");
    КонецЕсли;
КонецЦикла;

Метод Типы() отдаёт массив объектов Тип — по нему удобно бежать циклом. Метод СодержитТип() короче, когда достаточно проверить один конкретный тип.

Описание типов хранится у многих объектов платформы:

  • у реквизита метаданных — свойство Тип (это и есть ОписаниеТипов);
  • у колонки таблицы значений — свойство ТипЗначения;
  • у реквизита формы и у параметра запроса — тоже ОписаниеТипов.

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

Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
    Описание = Колонка.ТипЗначения;
    Если Описание.Типы().Количество() = 0 Тогда
        Сообщить(Колонка.Имя + " — тип не ограничен (любой)");
    Иначе
        Сообщить(СтрШаблон("%1 — типов: %2",
            Колонка.Имя, Описание.Типы().Количество()));
    КонецЕсли;
КонецЦикла;

Пустой массив Типы() означает, что колонка принимает значение любого типа — такое бывает, когда колонку добавили без явного указания типа.

Перебрать типы всех реквизитов справочника можно прямо по метаданным:

Для Каждого Реквизит Из Метаданные.Справочники.Контрагенты.Реквизиты Цикл
    Сообщить(СтрШаблон("%1 — типов: %2",
        Реквизит.Имя, Реквизит.Тип.Типы().Количество()));
КонецЦикла;

Здесь СтрШаблон сам приводит число к строке — склеивать строку с числом через + нельзя, будет ошибка приведения.

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

Во время отладки тип переменной показывает платформа — выдумывать код не нужно.

  1. Поставьте точку останова (клавиша F9 на строке) и запустите отладку.
  2. Когда выполнение остановится, откройте окно Табло (меню Отладка → Табло). Введите имя переменной — в колонке Тип появится её текущий тип.
  3. Для разового вычисления используйте Отладка → Вычислить выражение (Shift+F9): введите ТипЗнч(Переменная) и выполните — платформа покажет значение и тип результата.

Если нужно вывести тип в сообщениях по ходу работы без остановки, подойдёт Сообщить(СтрШаблон("%1", ТипЗнч(Значение))) — представление типа попадёт в окно сообщений.

Отладка внешних обработок требует включённой отладки в параметрах информационной базы, а подключение к работающему сеансу — прав на отладку. На рабочей базе это согласуют с администратором: отладка притормаживает сеанс.

Особенность планов видов характеристик

У планов видов характеристик тип значения не задан жёстко в метаданных — он свой у каждого элемента. Поэтому определять его нужно не по типу ссылки, а по стандартному реквизиту ТипЗначения.

ТипЗначения — это ОписаниеТипов, которое хранится прямо в элементе плана видов характеристик и говорит, значения каких типов допустимы для данной характеристики (субконто, свойства, показателя):

ОписаниеТ = ВидХарактеристикиСсылка.ТипЗначения;

Если ОписаниеТ.СодержитТип(Тип("Число")) Тогда
    Сообщить("Характеристика числовая");
ИначеЕсли ОписаниеТ.СодержитТип(Тип("Дата")) Тогда
    Сообщить("Характеристика — дата");
КонецЕсли;

Набор типов, из которого вообще можно выбирать при настройке вида характеристики, задаётся в метаданных плана — свойство Тип значения характеристик. А конкретный тип отдельной характеристики лежит в её реквизите ТипЗначения. Не путайте эти два уровня: метаданные задают рамку допустимых типов, элемент — фактический тип своего значения.

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

Тип значения можно выяснить и прямо в запросе — особенно когда поле составное: субконто регистра бухгалтерии, значение характеристики, реквизит с несколькими типами. Для этого есть функции ТИПЗНАЧЕНИЯ() и ТИП().

ТИПЗНАЧЕНИЯ(Поле) возвращает тип значения в этом поле строки. Сравнивают его с ТИП(...), где имя пишется без суффикса Ссылка:

ВЫБРАТЬ
    Движения.Субконто1 КАК Субконто,
    ТИПЗНАЧЕНИЯ(Движения.Субконто1) КАК ТипСубконто
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Обороты КАК Движения
ГДЕ
    ТИПЗНАЧЕНИЯ(Движения.Субконто1) = ТИП(Справочник.Контрагенты)

Когда поле составного типа нужно привести к конкретному, применяют ВЫРАЗИТЬ(... КАК ...). Это позволяет обратиться к реквизитам приведённого типа:

ВЫБРАТЬ
    ВЫРАЗИТЬ(Таблица.Субконто1 КАК Справочник.Контрагенты).ИНН КАК ИНН
ИЗ
    ...

Если тип поля заранее неизвестен, сначала отберите нужные строки по ТИПЗНАЧЕНИЯ(...) = ТИП(...), а уже потом применяйте ВЫРАЗИТЬ — иначе для строк другого типа реквизит вернёт NULL.

Типичные ошибки при определении типа

  • 🔴 Сравнение со строкой вместо Тип(). Запись ТипЗнч(Значение) = "СправочникСсылка.Контрагенты" всегда даёт Ложь: слева объект Тип, справа строка. Нужно Тип("СправочникСсылка.Контрагенты").
  • 🔴 Путаница Ссылка и Объект. В обработке проведения или в модуле объекта значение имеет тип ...Объект.<Имя>, а не ...Ссылка.<Имя>. Проверка на ссылочный тип там не сработает.
  • 🔴 Вызов Метаданные() на примитиве. У числа, строки, булева нет метода Метаданные(). Сначала убедитесь, что значение ссылочное — например, через ТипВсеСсылки().СодержитТип(...).
  • 🔴 Опечатка в имени типа. Тип("Справочник.Контрагенты") — ошибка: у ссылки класс пишется как СправочникСсылка. А несуществующее имя в Тип("...") вызовет исключение во время выполнения.
  • 🔴 Склейка числа со строкой. "Типов: " + Количество падает на приведении. Используйте СтрШаблон или Строка(Количество).

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

Чем `ТипЗнч()` отличается от `Метаданные()`?
ТипЗнч() возвращает тип значения (объект Тип) и работает с любыми данными, включая примитивы. Метаданные() возвращает объект метаданных с именем, реквизитами и табличными частями, но доступен только у объектов конфигурации — у числа или строки его нет.
Как получить строковое имя типа ссылки?
Через метаданные: Ссылка.Метаданные().ПолноеИмя() даст Справочник.Контрагенты, а Ссылка.Метаданные().Имя — короткое Контрагенты. Это надёжнее, чем преобразовывать сам объект Тип в строку.
Как проверить, что значение — ссылка на любой справочник, не перечисляя все?
Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)). Метод ТипВсеСсылки() есть у менеджеров Справочники, Документы, ПланыСчетов и других ссылочных объектов.
Почему у пустой ссылки всё равно есть тип?
Пустая ссылка создаётся для конкретного справочника или документа и хранит его тип. Поэтому ТипЗнч(ПустаяСсылка) вернёт нормальный ссылочный тип, а .Метаданные() на ней отработает корректно.
Как узнать тип значения конкретной характеристики в плане видов характеристик?
Читайте стандартный реквизит ТипЗначения элемента — это ОписаниеТипов. Проверяйте вхождение нужного типа методом СодержитТип().
Проверьте себя
Какая функция возвращает тип произвольного значения?
Как правильно сравнить тип ссылки с эталоном?
Где хранится фактический тип значения характеристики?