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

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

Как в 1С проверить, что значение является документом

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

Задача «проверить, что это документ» возникает в 1С постоянно: при обходе выборки, в процедурах обмена, при написании универсальных обработчиков и подписок на события. У разработчика есть переменная неизвестного типа, и нужно понять, является ли она ссылкой на документ, объектом документа или чем-то совершенно иным — справочником, перечислением, строкой.

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

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

Определение типа значения через ТипЗнч и Тип

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

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

// Это ссылка на документ «Реализация товаров и услуг»

КонецЕсли;

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

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

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

Проверка «это вообще документ» через ТипВсеСсылки

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

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

// Значение — ссылка на какой-либо документ

КонецЕсли;

Это самый короткий способ ответить на вопрос «это документ или нет» без перечисления видов. Аналогичные методы есть у других классов: Справочники.ТипВсеСсылки(), Перечисления.ТипВсеСсылки(), ПланыВидовХарактеристик.ТипВсеСсылки(). Комбинируя их, можно построить универсальный классификатор значений.

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

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

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

МетаОбъект = Метаданные.НайтиПоТипу(ТипЗнч(Значение));

Если МетаОбъект <> Неопределено

И Метаданные.Документы.Содержит(МетаОбъект) Тогда

// Значение относится к документам (ссылка или объект)

КонецЕсли;

Обязательно проверяйте результат НайтиПоТипу() на Неопределено: для примитивных типов (строка, число, дата) и некоторых системных значений метод возвращает Неопределено, и обращение Метаданные.Документы.Содержит(Неопределено) вызовет ошибку.

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

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

Как отличить ссылку от объекта документа

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

Надёжный приём — сравнение имени типа через строковое представление или проверка по метаданным с дополнительным анализом:

Если ТипЗнч(Значение) = Тип("ДокументОбъект." + МетаОбъект.Имя) Тогда

// Это объект, его можно изменять и записывать

Иначе

// Это ссылка; для изменений нужен ПолучитьОбъект()

КонецЕсли;

Альтернатива — попытка обращения к свойству Ссылка: у объекта документа оно есть и указывает на саму ссылку. Но прямое сравнение типов читается яснее и не зависит от контекста исполнения.

Проверка в запросе: ссылка на конкретный вид документа

Когда проверка нужна внутри запроса — например, отобрать из составного реквизита только документы определённого вида — используется оператор ССЫЛКА:

ВЫБРАТЬ

Задачи.ДокументОснование

ИЗ

Задача.Задачи КАК Задачи

ГДЕ

Задачи.ДокументОснование ССЫЛКА Документ.ЗаказКлиента

Оператор ССЫЛКА проверяет принадлежность ссылки указанному виду документа. Проверить «любой документ» в запросе напрямую нельзя — придётся перечислять виды через ИЛИ либо решать задачу на уровне кода после выгрузки результата. Для отбора «только заполненные ссылки» используйте сравнение с пустой ссылкой конкретного вида.

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

ТипЗнч = Тип(...)

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

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

Лучший вариант для проверки «любая ссылка на документ»; не работает с ДокументОбъект

Метаданные.НайтиПоТипу + Содержит

Универсально для ссылок и объектов, даёт доступ к имени вида; требует проверки на Неопределено и чуть длиннее

ССЫЛКА в запросе

Единственный способ фильтровать по виду на стороне СУБД; нельзя проверить «любой документ» без перечисления видов

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

Первая распространённая ошибка — сравнение типа со строкой: Если ТипЗнч(Значение) = "ДокументСсылка.Заказ" Тогда. Тип никогда не равен строке, условие всегда ложно, и ветка кода молча не выполняется. Сравнивайте тип с типом через функцию Тип().

Вторая ошибка — забыть про Неопределено и NULL. Вызов ТипЗнч(Неопределено) корректно вернёт тип «Неопределено», но последующее обращение к метаданным или реквизитам упадёт. Перед проверками полезно отсекать пустые значения функцией ЗначениеЗаполнено() или явным сравнением.

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

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

Проверка результата и границы применения

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

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

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

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

Ссылка на нужный вид документа
Норма

Все три способа (Тип, ТипВсеСсылки, метаданные) дают Истина

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

Проверка через ТипВсеСсылки возвращает Ложь — значит, пришёл объект, а не ссылка

Строка или число в переменной
Норма

НайтиПоТипу вернул Неопределено, ветка документа не выполнилась

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

Ошибка выполнения — не проверен результат НайтиПоТипу

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

Тип определён как документ, ПолучитьОбъект() вернул Неопределено, код это обработал

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

Падение при обращении к реквизитам ссылки

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

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

Составьте список имён видов и сравнивайте с именем метаданных: получите Метаданные.НайтиПоТипу(ТипЗнч(Значение)).Имя и проверьте вхождение в массив допустимых имён через Массив.Найти(). Это компактнее цепочки сравнений ТипЗнч = Тип(...) и легче расширяется.

Можно ли проверить вид документа по представлению ссылки (строке)?

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

Чем проверка через ТипВсеСсылки быстрее или медленнее других способов?

Разница в производительности между сравнением типов и обращением к метаданным несущественна для обычной бизнес-логики. Выбирайте способ по читаемости и покрытию случаев, а не по скорости. В массовых циклах имеет смысл кэшировать результат НайтиПоТипу(), чтобы не вызывать его повторно для одного и того же типа.

Как проверить, что значение — именно проведённый документ?

Сначала убедитесь, что это ссылка на документ, затем прочитайте реквизит Проведен: Значение.Проведен. Для объекта документа реквизит доступен напрямую. Учтите, что обращение к реквизиту ссылки — это обращение к базе, поэтому в циклах выгоднее выбирать признак проведения запросом.

Работает ли проверка типа на тонком клиенте и в веб-клиенте?

Функции ТипЗнч(), Тип() и сравнение типов доступны на клиенте. А вот обращение к Метаданные и менеджерам объектов ограничено: полноценная проверка через метаданные выполняется на сервере. В клиент-серверном коде выносите такие проверки в серверные процедуры.

Что делать, если тип значения заранее неизвестен и может быть составным?

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

Итог

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

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