К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как в 1С определить тип объекта: документ или справочник

Как в 1С определить тип объекта — документ или справочник: методы Метаданные(), ТипЗнч(), сравнение через МенеджерТипа, примеры кода для запросов и СКД.

Задача определить, является ли объект документом или справочником, возникает у разработчика 1С постоянно: при написании универсальных обработок, обменов, проверок ссылок в регистрах, печатных форм и расширений. Платформа 1С:Предприятие предоставляет несколько штатных способов получить тип объекта — через метаданные, функции глобального контекста и средства работы с запросами. Каждый способ имеет свою область применения и ограничения.

Ключевой принцип: в 1С «тип» и «вид» объекта — разные вещи. Тип СправочникСсылка говорит лишь о том, что перед нами ссылка на какой-то справочник, а конкретный вид (например, «Номенклатура» или «Контрагенты») определяется через метаданные. Понимание этой двухуровневой модели избавляет от большинства ошибок при определении типа.

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

Чем тип отличается от вида объекта в 1С

В платформе 1С любой прикладной объект описывается двумя уровнями. Первый — класс типа: ДокументСсылка, ДокументОбъект, СправочникСсылка, СправочникОбъект и так далее. Второй — конкретный вид в конфигурации: документ «РеализацияТоваровУслуг», справочник «Номенклатура». Функция ТипЗнч() возвращает только первый уровень, а вид определяется через метаданные.

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

Способ 1. Определение вида через метаданные

Универсальный и самый надёжный приём — получить объект метаданных по типу значения и проверить, в какую коллекцию конфигурации он входит. Код работает одинаково для ссылок и объектов:

Мета = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));

Если Мета = Неопределено Тогда

// Тип не является прикладным объектом конфигурации

ИначеЕсли Метаданные.Документы.Содержит(Мета) Тогда

// Это документ, имя вида: Мета.Имя

ИначеЕсли Метаданные.Справочники.Содержит(Мета) Тогда

// Это справочник, имя вида: Мета.Имя

КонецЕсли;

Такой подход не требует знания конкретных имён видов заранее, поэтому идеален для универсальных обработок и расширений. Дополнительно через Мета.ПолноеИмя() можно получить строку вида «Документ.РеализацияТоваровУслуг» — её удобно использовать для логирования и в запросах через представление типа.

Если конфигурация типовая, в общем модуле «ОбщегоНазначения» обычно уже есть готовые функции: ЭтоДокумент(МетаданныеОбъекта), ЭтоСправочник(МетаданныеОбъекта), а также ВидОбъектаПоСсылке(Ссылка) в БСП. Перед написанием своего кода проверьте наличие этих функций — повторное изобретение усложняет сопровождение.

bsl
Функция ЭтоДокумент(Ссылка) Экспорт
    Мета = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
    Возврат Мета <> Неопределено И Метаданные.Документы.Содержит(Мета);
КонецФункции

Способ 2. Быстрая проверка через ТипЗнч()

Когда вид объекта известен заранее и нужно лишь сравнить, достаточно функции ТипЗнч() и конструктора Тип():

Если ТипЗнч(Ссылка) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда

// Точное совпадение вида

КонецЕсли;

Этот способ самый быстрый и читаемый, но жёстко привязан к имени вида. Если документ переименуют в конфигураторе, строка в Тип() станет невалидной — на этапе компиляции модуля платформа это отловит, но в динамически формируемом коде (через Выполнить) ошибка проявится только в рантайме.

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

Способы определения типа

Метаданные.НайтиПоТипу()

Универсально, работает с любыми объектами конфигурации. Чуть медленнее прямого сравнения, требует проверки на Неопределено.

ТипЗнч() + Тип()

Быстро и наглядно, но привязано к конкретному имени вида. Подходит для точечных проверок.

Документы.ТипВсеСсылки()

Проверяет только класс (документ/справочник), без имени вида. Хорош для фильтрации составных типов.

Запрос с РЕФЕРЕНС / ТИПЗНАЧЕНИЯ

Единственный вариант внутри запроса и СКД, где встроенный язык недоступен.

Способ 3. Определение типа в запросе

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

ВЫБОР

КОГДА Таб.Ссылка ССЫЛКА Документ.РеализацияТоваровУслуг

ТОГДА "Документ реализации"

КОГДА Таб.Ссылка ССЫЛКА Справочник.Номенклатура

ТОГДА "Справочник номенклатуры"

ИНАЧЕ "Другой тип"

КОНЕЦ

Оператор ССЫЛКА (в русской и английской нотации — РЕФЕРЕНС / REFS) возвращает Истина, если ссылка принадлежит указанному виду. Это стандартный приём для полей составного типа, например «ДокументОснование», куда могут записываться разные документы и иногда ссылки на справочники.

В СКД те же конструкции доступны в выражениях вычисляемых полей и отборов. Учтите: проверка через ССЫЛКА на составном поле может отключать некоторые оптимизации СУБД, поэтому на больших таблицах предпочтительнее фильтровать по типу в параметрах виртуальных таблиц.

Типовые сценарии: от ссылки до полной проверки

Универсальная обработка ссылок произвольного типа

Когда процедура принимает параметр неизвестного типа (например, из формы выбора или файла обмена), порядок действий такой: сначала проверить, что значение — ссылка прикладного объекта, затем определить класс, затем вид. Пропуск первого шага приводит к ошибкам, когда в параметр попадает строка, число или Неопределено.

Порядок определения вида объекта
  1. 1
    Проверьте, что значение заполнено и является ссылкой: Справочники.ТипВсеСсылки().СодержитТип() или Документы.ТипВсеСсылки().СодержитТип().
  2. 2
    Получите метаданные: Мета = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка)).
  3. 3
    Проверьте принадлежность коллекции: Метаданные.Документы.Содержит(Мета) или Метаданные.Справочники.Содержит(Мета).
  4. 4
    Используйте Мета.Имя для ветвления логики и Мета.ПолноеИмя() для сообщений.
  5. 5
    Проверьте результат на тестовых ссылках обоих классов и на значении Неопределено.

Работа с регистрами и составными типами

В измерениях и реквизитах регистров часто встречаются составные типы. Перед обращением к реквизиту через точку обязательно определите вид значения: у документа есть Дата и Номер, у справочника — Код и Наименование, и попытка прочитать несуществующий реквизит вызовет исключение. Безопасная альтернатива — обращение через метаданные: Мета.Реквизиты.Найти("Организация") покажет, есть ли нужный реквизит у данного вида.

Типичные ошибки
01
Вызов ПолучитьОбъект() только ради определения типа — лишнее чтение из базы и риск блокировок; вид определяется по ссылке.
02
Сравнение строки имени типа вместо значения типа — строковые сравнения хрупки и не ловятся компилятором.
03
Отсутствие проверки Метаданные.НайтиПоТипу() на Неопределено — для примитивных типов функция возвращает Неопределено, и следующий вызов падает.
04
Использование ССЫЛКА в запросе без учёта битых ссылок — битая ссылка имеет тип, но обращение к её реквизитам даёт NULL.

Проверка результата и отладка

Убедиться, что определение типа работает корректно, можно в консоли кода (внешняя обработка «Консоль кода» из инструментов разработчика или аналог): подставьте реальные ссылки из базы, значение Неопределено, битую ссылку и значение примитивного типа. Все четыре случая должны обрабатываться без исключений.

Для быстрой визуальной проверки прямо в коде удобно выводить Ссылка.Метаданные().Имя — у ссылочных значений метод Метаданные() доступен напрямую и возвращает тот же объект метаданных, что и НайтиПоТипу, но короче в записи. Это самый лаконичный способ получить вид, когда точно известно, что значение — ссылка прикладного объекта.

Контрольные точки

Как проверить корректность кода

Передача ссылки на документ
Норма

Метаданные.Документы.Содержит() возвращает Истина, имя вида корректное

Тревожный признак

Функция возвращает Неопределено или неверный класс

Передача Неопределено или числа
Норма

Код возвращает Ложь или ветку по умолчанию без исключения

Тревожный признак

Возникает ошибка обращения к метаданным

Битая ссылка
Норма

Вид определяется, обращение к реквизитам защищено проверкой

Тревожный признак

Падение при чтении реквизитов

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

Вызов Метаданные.НайтиПоТипу() в цикле по тысячам строк заметно дешевле, чем чтение объектов, но всё же не бесплатен. Если тип в цикле не меняется, вынесите вычисление за его пределы или кэшируйте результат в соответствии «тип → метаданные». В серверных процедурах с массовой обработкой это даёт ощутимый выигрыш.

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

Итог

Что важно запомнить

Вид объекта определяется через метаданные (НайтиПоТипу + Содержит), класс — через ТипВсеСсылки() или ТипЗнч(). В запросах используйте ССЫЛКА и ТИПЗНАЧЕНИЯ. Никогда не читайте объект ради определения типа и всегда проверяйте результат НайтиПоТипу на Неопределено.

FAQ

Как определить тип, если ссылка битая?

Битая ссылка сохраняет свой тип, поэтому Метаданные.НайтиПоТипу() и оператор ССЫЛКА в запросе работают корректно. Проблемы начинаются при обращении к реквизитам — они вернут NULL или вызовут ошибку. Проверяйте существование объекта через Ссылка.ПолучитьОбъект() = Неопределено или запросом по ссылке.

Чем отличается ТипЗнч() от Метаданные.НайтиПоТипу()?

ТипЗнч() возвращает объект «Тип» — класс значения (например, ДокументСсылка.РеализацияТоваровУслуг). НайтиПоТипу() по этому типу находит объект метаданных конфигурации, через который доступны имя вида, реквизиты, табличные части и принадлежность к коллекции. Для ветвления логики обычно нужны метаданные, для точного сравнения — тип.

Можно ли определить тип на тонком клиенте без сервера?

Частично: ТипЗнч() и сравнение с Тип() работают на клиенте. Полноценный анализ через метаданные требует сервера, так как коллекция Метаданные на тонком клиенте недоступна. Практичный приём — серверная функция, возвращающая имя вида строкой.

Как проверить, что значение вообще ссылка, а не объект?

Сравните тип с менеджером ссылок: Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)). Для объектов используется ТипВсеОбъекты() у соответствующих менеджеров либо проверка через метаданные с учётом того, что у объекта тип будет ДокументОбъект/СправочникОбъект.

Как определить тип в СКД без написания кода?

В вычисляемом поле или отборе СКД используйте выражение языка запросов: условие вида «Поле ССЫЛКА Документ.Имя» или функцию ТИПЗНАЧЕНИЯ(Поле) для вывода типа. В настройках отбора составное поле можно фильтровать по конкретному виду через тот же оператор ССЫЛКА.

Есть ли готовые функции в типовых конфигурациях?

Да, в конфигурациях на Библиотеке стандартных подсистем есть общий модуль «ОбщегоНазначения» с функциями ЭтоДокумент(), ЭтоСправочник(), ВидОбъектаПоСсылке() и рядом смежных. Используйте их вместо собственных реализаций — это упрощает обновление и делает код понятнее другим разработчикам.