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

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

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

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

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

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

Универсального встроенного предиката вида «ЭтоСсылка()» в платформе нет, поэтому разработчики используют несколько обходных приемов. Ниже разобраны рабочие способы с готовым кодом, их ограничения и типичные ошибки.

Что считается ссылочным типом в 1С

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

  • СправочникСсылка.<ИмяСправочника>;
  • ДокументСсылка.<ИмяДокумента>;
  • ПланВидовХарактеристикСсылка;
  • ПланСчетовСсылка;
  • ПланВидовРасчетаСсылка;
  • ПланОбменаСсылка;
  • ПеречислениеСсылка;
  • БизнесПроцессСсылка и ЗадачаСсылка;
  • ТочкаМаршрутаБизнесПроцессаСсылка.

Важно не путать ссылку с объектом. ДокументОбъект — это программный объект в памяти, доступный для изменения, а ДокументСсылка — только идентификатор записи. Типы «объект», «менеджер», «список» ссылочными не являются, хотя связаны с теми же метаданными. Проверка «это ссылка» должна отличать именно Ссылка от Объект, иначе логика обхода данных развалится.

Способ 1. Проверка через коллекции ТипВсеСсылки()

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

Функция ЭтоСсылка(Значение) Экспорт

ТипЗначения = ТипЗнч(Значение);

Возврат Справочники.ТипВсеСсылки().СодержитТип(ТипЗначения)

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

Или Перечисления.ТипВсеСсылки().СодержитТип(ТипЗначения)

Или ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(ТипЗначения)

Или ПланыСчетов.ТипВсеСсылки().СодержитТип(ТипЗначения)

Или ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(ТипЗначения)

Или ПланыОбмена.ТипВсеСсылки().СодержитТип(ТипЗначения)

Или БизнесПроцессы.ТипВсеСсылки().СодержитТип(ТипЗначения)

Или Задачи.ТипВсеСсылки().СодержитТип(ТипЗначения);

КонецФункции

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

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

1c
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(МоеЗначение)) Тогда
    // значение — ссылка на справочник
КонецЕсли;

Способ 2. Проверка через XMLТипЗнч

Компактный альтернативный прием — сериализовать тип значения в XML-представление и посмотреть на имя типа. У ссылочных типов XML-имя содержит суффикс вида CatalogRef, DocumentRef, EnumRef и т.п., тогда как у примитивов — string, decimal, boolean, datetime.

Функция ЭтоСсылкаЧерезXML(Значение)

ТипXML = XMLТипЗнч(Значение);

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

Возврат Ложь;

КонецЕсли;

ИмяТипа = ТипXML.ИмяТипа;

Возврат СтрНайти(ИмяТипа, "Ref.") > 0

Или СтрНайти(ИмяТипа, "Ref,") > 0;

КонецФункции

Этот вариант короче и не требует перечисления менеджеров, но он завязан на формат имен XML-типов и менее читаем. Кроме того, XMLТипЗнч вернет Неопределено для значений, не имеющих XML-представления (например, таблица значений), поэтому проверка на Неопределено обязательна.

Способ 3. Определение по типу реквизита метаданных

Иногда нужно проверить не конкретное значение, а тип реквизита объекта метаданных — например, при построении универсального обхода всех реквизитов справочника. В этом случае работают с объектом ОписаниеТипов из метаданных.

Для Каждого Реквизит Из Метаданные.Справочники.Номенклатура.Реквизиты Цикл

Для Каждого Тип Из Реквизит.Тип.Типы() Цикл

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

// реквизит может хранить ссылку на справочник

КонецЕсли;

КонецЦикла;

КонецЦикла;

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

Как проверить, что ссылка не битая

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

Для проверки используют два подхода. Первый — запрос к базе через свойство ПолучитьОбъект() с обработкой Неопределено, либо запросом с проверкой на NULL. Второй, более быстрый при массовой обработке, — сравнение строкового представления ссылки: у битых ссылок оно имеет вид «<Объект не найден> (…)».

Функция СсылкаСуществует(Ссылка)

Запрос = Новый Запрос(

"ВЫБРАТЬ ПЕРВЫЕ 1 ИСТИНА

|ИЗ " + Ссылка.Метаданные().ПолноеИмя() + " КАК Т

|ГДЕ Т.Ссылка = &Ссылка");

Запрос.УстановитьПараметр("Ссылка", Ссылка);

Возврат Не Запрос.Выполнить().Пустой();

КонецФункции

Проверка на пустую ссылку

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

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

// ссылка заполнена

КонецЕсли;

// явное сравнение с пустой ссылкой

Если Контрагент = Справочники.Контрагенты.ПустаяСсылка() Тогда

// ссылка пустая

КонецЕсли;

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

Типичные ошибки
01
Сравнение ссылки с Неопределено вместо ПустаяСсылка() — пустые ссылки не отлавливаются
02
Передача значения вместо ТипЗнч(Значение) в СодержитТип() — проверка молча возвращает Ложь
03
Использование ПолучитьОбъект() для массовой проверки существования — сильная нагрузка на базу
04
Проверка ссылочности по строковому представлению значения — ломается при смене форматов и локализации
05
Игнорирование Неопределено у XMLТипЗнч() — ошибка выполнения на несериализуемых типах

Какой способ выбрать

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

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

ТипВсеСсылки() + СодержитТип

Надежно и читаемо; требует перечисления всех видов ссылочных объектов

XMLТипЗнч + анализ имени типа

Компактно и универсально; зависит от формата XML-имен, нужна проверка на Неопределено

Анализ метаданных (ОписаниеТипов)

Подходит для проверки типов реквизитов, а не конкретных значений

Строковое представление значения

Только для диагностики битых ссылок; не подходит для определения типа

Итог

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

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

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

Есть ли в 1С встроенная функция ЭтоСсылка()?

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

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

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

Чем ссылка отличается от уникального идентификатора?

Ссылка — типизированное значение, привязанное к конкретному виду объекта. Уникальный идентификатор (GUID) — только строка-идентификатор без типа. Получить GUID ссылки можно методом Ссылка.УникальныйИдентификатор(), а обратно — методом ПолучитьСсылку(Новый УникальныйИдентификатор(...)) у менеджера объекта.

Как проверить ссылочный тип в запросе?

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

Почему перечисление считается ссылочным типом?

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