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

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

Как получить тип документа по ссылке в 1С

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

Во встроенном языке 1С ссылка на документ — это объект специального вида, который содержит уникальный идентификатор и указание на вид документа. Часто в алгоритмах нужно узнать, документом какого вида является переданная ссылка: например, чтобы в общей процедуре по-разному обработать «Реализацию товаров» и «Поступление товаров», или чтобы проверить, допустим ли тип перед заполнением реквизита.

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

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

Что такое ссылка на документ и где хранится её тип

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

Это важно с точки зрения производительности: получение типа по ссылке — лёгкая операция, в отличие от вызова Ссылка.ПолучитьОбъект(), который читает весь документ из базы со всеми табличными частями. Если задача — только выяснить вид документа, объект получать не нужно.

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

Способ 1: получить имя вида через Метаданные()

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

ИмяВида = Ссылка.Метаданные().Имя;

// Например: "РеализацияТоваровУслуг"

ПолноеИмя = Ссылка.Метаданные().ПолноеИмя();

// Например: "Документ.РеализацияТоваровУслуг"

Представление = Ссылка.Метаданные().Синоним;

// Например: "Реализация товаров и услуг"

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

Ограничение: если переменная содержит Неопределено, обращение к Метаданные() вызовет ошибку «Значение не является значением объектного типа». Перед вызовом проверяйте, что значение заполнено.

bsl
Если ЗначениеЗаполнено(Ссылка) Тогда
    ИмяВида = Ссылка.Метаданные().Имя;
Иначе
    ИмяВида = "";
КонецЕсли;

Способ 2: сравнение типов через ТипЗнч() и Тип()

Когда нужно не получить строку, а проверить «является ли ссылка документом конкретного вида», правильнее использовать функции ТипЗнч() и Тип(). Это быстрее, чем сравнение строк, и устойчиво к переименованию объектов при рефакторинге, если код правки проходит через конфигуратор.

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

// Обработка реализации

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

// Обработка поступления

КонецЕсли;

Проверку «это вообще документ, а не справочник» делают через менеджер типа: Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Ссылка)). Это полезно в универсальных обработчиках, куда могут попадать ссылки разных классов.

Обратите внимание: сравнивать ТипЗнч() со строкой нельзя — сравнение сработает только с объектом типа «Тип», полученным через Тип(). Проверка ТипЗнч(Ссылка) = "ДокументСсылка.Реализация" всегда вернёт ложь.

Сравнение способов

Ссылка.Метаданные().Имя

Возвращает строку с именем вида. Подходит для сообщений, журналов и динамических обращений. Не подходит для строгой проверки типа.

ТипЗнч(Ссылка) = Тип(...)

Строгое сравнение типов. Лучший выбор для ветвления логики, но не даёт строкового представления.

Запрос с ТИПЗНАЧЕНИЯ

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

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

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

ВЫБРАТЬ

СвязанныеДокументы.Документ КАК Документ,

ТИПЗНАЧЕНИЯ(СвязанныеДокументы.Документ) КАК ТипДокумента

ИЗ

РегистрСведений.СвязанныеДокументы КАК СвязанныеДокументы

ГДЕ

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

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

Важный нюанс: ТИПЗНАЧЕНИЯ() в запросе возвращает значение типа «Тип», которое нельзя напрямую вывести как строку в результат запроса для последующего сравнения строками. Если нужна строка имени вида для каждой строки выборки, получайте её уже в обходе результата через Выборка.Документ.Метаданные().Имя.

Как проверить результат и не ошибиться

После определения типа полезно убедиться, что логика отработала как ожидалось. Простейший способ отладки — вывести в сообщение и само значение, и его тип: Сообщить(Строка(Ссылка) + " — " + ТипЗнч(Ссылка)). Представление типа выводится в виде «Реализация товаров и услуг» или технического имени, что сразу показывает, что именно пришло в процедуру.

В толстом клиенте и конфигураторе удобно использовать табло (отладчик): добавьте выражение ТипЗнч(Ссылка) и Ссылка.Метаданные().ПолноеИмя() — оба вычисляются без обращения к базе.

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

Как проверить результат

Что вернуло Метаданные().Имя
Норма

Строка с именем вида из конфигуратора, например «РеализацияТоваровУслуг»

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

Ошибка «Значение не является значением объектного типа» — переменная содержит Неопределено

Сравнение ТипЗнч с Тип()
Норма

Условие срабатывает для документов нужного вида и не срабатывает для чужих

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

Условие никогда не истинно — вероятно, сравнение идёт со строкой, а не с Тип()

Отбор в запросе через ССЫЛКА
Норма

В выборку попадают только документы указанного вида

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

Пустой результат при заведомо существующих документах — проверьте имя вида в конфигураторе

Типичные ошибки и ограничения

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

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

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

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

Практический сценарий: обработчик для разных видов документов

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

Процедура ОбработатьДокумент(Ссылка) Экспорт

Если Не ЗначениеЗаполнено(Ссылка) Тогда

Возврат;

КонецЕсли;

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

ВызватьИсключение "Ожидалась ссылка на документ";

КонецЕсли;

ИмяВида = Ссылка.Метаданные().Имя;

Если ИмяВида = "РеализацияТоваровУслуг" Тогда

// логика для реализации

ИначеЕсли ИмяВида = "ПоступлениеТоваровУслуг" Тогда

// логика для поступления

Иначе

// вид не поддерживается — фиксируем в журнале

КонецЕсли;

КонецПроцедуры

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

Такой каркас безопасен: он не падает на пустых значениях, явно отсекает неподдерживаемые виды и оставляет место для журналирования. Если видов много, вместо цепочки Если...ИначеЕсли удобнее соответствие, где ключ — имя вида, а значение — имя процедуры-обработчика.

Часто задаваемые вопросы

Как получить тип документа по строковому представлению ссылки?

Надёжного способа восстановить тип из строки «Реализация товаров и услуг 00БП-000123 от ...» нет — это пользовательское представление, а не техническое значение. Если есть GUID, ссылку можно восстановить через Документы.ИмяВида.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаGUID)), но вид документа при этом нужно знать заранее или перебирать все менеджеры документов.

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

Да. Метод Ссылка.Метаданные() и функция ТипЗнч() работают в клиентском контексте управляемых форм, если реквизит доступен на клиенте. Обращения к базе данных при этом не происходит, поэтому серверный вызов не требуется.

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

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

Как определить тип у значения, которое может быть Неопределено?

Сначала проверьте значение: Если Ссылка = Неопределено Тогда ... или ЗначениеЗаполнено(Ссылка). У Неопределено нет метода Метаданные(), и обращение к нему вызовет ошибку выполнения. После проверки можно безопасно определять тип любым из способов.

Как в запросе выбрать документы нескольких конкретных видов?

Используйте перечисление условий через ИЛИ: ГДЕ Документ ССЫЛКА Документ.РеализацияТоваровУслуг ИЛИ Документ ССЫЛКА Документ.ПоступлениеТоваровУслуг. Альтернатива — сравнение ТИПЗНАЧЕНИЯ(Документ) В (...), но вариант со ССЫЛКА обычно читается лучше и эффективнее использует индексы.

Работает ли Метаданные() у битой ссылки?

Да. Битая ссылка (значение вида «Объект не найден») сохраняет и идентификатор, и вид документа, поэтому Метаданные().Имя и ТипЗнч() отработают корректно. Ошибки возникнут только при попытке прочитать реквизиты или получить объект. Проверить «битость» можно сравнением Ссылка.ПолучитьОбъект() = Неопределено или через запрос.

Итог

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

Тип документа хранится в самой ссылке, поэтому ПолучитьОбъект() не нужен. Для строки имени вида используйте Ссылка.Метаданные().Имя, для строгой проверки — ТипЗнч(Ссылка) = Тип("ДокументСсылка.ИмяВида"), в запросах — ССЫЛКА Документ.ИмяВида. Всегда проверяйте значение на Неопределено перед обращением к методам ссылки.