Разработка и Конфигурация · 9 мин
Как определить ссылочный тип или нет в 1С
Разбираем, как определить, является ли тип значения ссылочным в 1С: метод СсылкаСуществует, Справочники.ТипВсеСсылки, проверка через метаданные и типичные ошибки.
Задача определить, является ли значение ссылочным типом, возникает в 1С постоянно: при обходе реквизитов документов, универсальных выгрузках, проверке заполненности полей и написании обменов. Ошибка здесь приводит к падению кода: попытка обратиться к свойствам ссылки у примитивного значения вызывает исключение, а обратная ситуация ломает логику сравнений.
Ссылочные типы в 1С — это ссылки на объекты базы данных: справочники, документы, планы видов характеристик, планы счетов, планы видов расчета, перечисления, планы обмена, бизнес-процессы и задачи. Все остальное — строки, числа, даты, булево, массивы, структуры, таблицы значений — ссылочными не является, даже если визуально похоже на объект.
Универсального встроенного предиката вида «ЭтоСсылка()» в платформе нет, поэтому разработчики используют несколько обходных приемов. Ниже разобраны рабочие способы с готовым кодом, их ограничения и типичные ошибки.
Что считается ссылочным типом в 1С
Ссылочный тип — это тип, значение которого представляет собой ссылку на запись в базе данных. К нему относятся:
- СправочникСсылка.<ИмяСправочника>;
- ДокументСсылка.<ИмяДокумента>;
- ПланВидовХарактеристикСсылка;
- ПланСчетовСсылка;
- ПланВидовРасчетаСсылка;
- ПланОбменаСсылка;
- ПеречислениеСсылка;
- БизнесПроцессСсылка и ЗадачаСсылка;
- ТочкаМаршрутаБизнесПроцессаСсылка.
Важно не путать ссылку с объектом. ДокументОбъект — это программный объект в памяти, доступный для изменения, а ДокументСсылка — только идентификатор записи. Типы «объект», «менеджер», «список» ссылочными не являются, хотя связаны с теми же метаданными. Проверка «это ссылка» должна отличать именно Ссылка от Объект, иначе логика обхода данных развалится.
Способ 1. Проверка через коллекции ТипВсеСсылки()
Классический и наиболее корректный прием — использовать методы вида Справочники.ТипВсеСсылки(). Каждый менеджер ссылочного объекта метаданных возвращает описание типов, содержащее все ссылочные типы данного вида. Если тип проверяемого значения входит в это описание — значение ссылочное.
Функция ЭтоСсылка(Значение) Экспорт
ТипЗначения = ТипЗнч(Значение);
Возврат Справочники.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или Документы.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или Перечисления.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или ПланыСчетов.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или ПланыОбмена.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или БизнесПроцессы.ТипВсеСсылки().СодержитТип(ТипЗначения)
Или Задачи.ТипВсеСсылки().СодержитТип(ТипЗначения);
КонецФункции
Способ безопасен: он не обращается к базе данных, не бросает исключений и корректно работает с пустыми ссылками. Недостаток — многословность и необходимость перечислять все виды объектов. Если в конфигурации не используются, например, бизнес-процессы, соответствующую строку можно убрать.
Обратите внимание: метод СодержитТип() принимает именно тип (результат ТипЗнч), а не само значение. Передача значения вместо типа — частая ошибка, которая молча дает неверный результат.
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(МоеЗначение)) Тогда
// значение — ссылка на справочник
КонецЕсли;Способ 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 ИСТИНА
|ИЗ " + Ссылка.Метаданные().ПолноеИмя() + " КАК Т
|ГДЕ Т.Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Возврат Не Запрос.Выполнить().Пустой();
КонецФункции
Проверка на пустую ссылку
Пустая ссылка — это корректное ссылочное значение, у которого не заполнен идентификатор. Определить, что значение ссылочное, но пустое, стандартная функция ЗначениеЗаполнено() умеет сама: она вернет Ложь и для пустой ссылки, и для пустой строки. Но если нужно явно сравнить с пустой ссылкой конкретного вида, используют менеджер объекта.
Если ЗначениеЗаполнено(СтрокаТовара.Номенклатура) Тогда
// ссылка заполнена
КонецЕсли;
// явное сравнение с пустой ссылкой
Если Контрагент = Справочники.Контрагенты.ПустаяСсылка() Тогда
// ссылка пустая
КонецЕсли;
Типичная ошибка — сравнивать ссылку с Неопределено. Неопределено и пустая ссылка — разные значения: реквизит составного типа может содержать Неопределено, и проверка «= ПустаяСсылка()» его не отловит. В универсальном коде проверяйте оба варианта или используйте ЗначениеЗаполнено().
Какой способ выбрать
Выбор зависит от контекста. Для прикладного кода в типовой логике лучше подходит проверка через ТипВсеСсылки() — она явная, читаемая и не зависит от внутреннего представления типов. Для коротких сервисных функций допустим вариант через XMLТипЗнч. Для анализа структуры конфигурации — только работа с метаданными и ОписаниеТипов.
Сравнение способов проверки
Надежно и читаемо; требует перечисления всех видов ссылочных объектов
Компактно и универсально; зависит от формата XML-имен, нужна проверка на Неопределено
Подходит для проверки типов реквизитов, а не конкретных значений
Только для диагностики битых ссылок; не подходит для определения типа
Что важно запомнить
Ссылочный тип надежно определяется через СодержитТип() по коллекциям ТипВсеСсылки() менеджеров объектов. Пустая ссылка — не Неопределено, существование объекта проверяйте запросом, а не ПолучитьОбъект() в цикле.
Частые вопросы
Есть ли в 1С встроенная функция ЭтоСсылка()?
Нет, встроенного предиката в языке нет. В типовых конфигурациях на базе БСП есть функция ОбщегоНазначения.ЭтоСсылка(Тип), которая внутри использует именно проверку через ТипВсеСсылки(). В собственной конфигурации такую функцию пишут самостоятельно по образцу из статьи.
Как определить вид объекта по ссылке?
Через метаданные: Ссылка.Метаданные() вернет объект метаданных, а Ссылка.Метаданные().ПолноеИмя() — строку вида «Справочник.Номенклатура» или «Документ.РеализацияТоваровУслуг». Это работает только у ссылочных значений, поэтому сначала убедитесь, что тип ссылочный.
Чем ссылка отличается от уникального идентификатора?
Ссылка — типизированное значение, привязанное к конкретному виду объекта. Уникальный идентификатор (GUID) — только строка-идентификатор без типа. Получить GUID ссылки можно методом Ссылка.УникальныйИдентификатор(), а обратно — методом ПолучитьСсылку(Новый УникальныйИдентификатор(...)) у менеджера объекта.
Как проверить ссылочный тип в запросе?
В языке запросов используют конструкцию ССЫЛКА: «ГДЕ Реквизит ССЫЛКА Справочник.Номенклатура» — условие истинно, если значение реквизита является ссылкой указанного вида. Также есть функция ТИПЗНАЧЕНИЯ(Реквизит) для сравнения с конкретным типом через ТИП().
Почему перечисление считается ссылочным типом?
Значения перечислений хранятся как записи служебной таблицы и имеют ссылку и GUID, поэтому ПеречислениеСсылка входит в ссылочные типы. При этом у перечислений нет метода ПолучитьОбъект() в обычном смысле прикладной логики изменения — их состав фиксируется в конфигураторе.