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