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