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