При активной работе в базах данных 1С:Предприятие пользователи и разработчики часто сталкиваются с неприятным явлением, когда вместо наименования элемента справочника или документа отображается загадочная надпись вида "Объект не найден (84:b803001e6704040911e3b207df365313)". В профессиональной среде это явление называют "битой ссылкой" или ссылкой на несуществующий объект.
В этой статье мы подробно разберем природу возникновения подобных ошибок, рассмотрим эффективные методы их поиска с помощью запросов, напишем программные обработчики на встроенном языке 1С, а также изучим стандартные инструменты платформы для исправления целостности базы данных.
Прежде чем перейти к методам поиска, давайте выясним причину появления таких записей. Битая ссылка формируется в тот момент, когда в таблице базы данных (например, в таблице регистра сведений) сохраняется уникальный идентификатор объекта (GUID), но сама запись в физической таблице этого объекта (справочника, документа или бизнес-процесса) отсутствует. Это происходит в следующих случаях:
Удалить() вместо штатной пометки на удаление и последующего контроля ссылочной целостности.Самый быстрый и производительный способ локализовать проблему в конкретном регистре или документе — это использование механизма левого соединения в запросах. Разберем по шагам логику этого метода. Для автоматизации такого процесса подойдёт обработка для поиска битых ссылок через запросы и восстановления объектов.
Когда мы обращаемся через точку к реквизиту ссылочного поля (например, ТипЦен.Код), платформа 1С "под капотом" делает левое соединение (LEFT JOIN) таблицы регистра с таблицей справочника по уникальному идентификатору. Если объект существует, поле заполнится реальным кодом. Если объект был удален, СУБД вернет значение NULL.
Давайте посмотрим на пример запроса для регистра сведений ЦеныНоменклатуры, где измерение ТипЦен содержит битые ссылки:
ВЫБРАТЬ
РС.Номенклатура,
РС.Характеристика,
РС.ТипЦен КАК БитаяСсылка
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК РС
ГДЕ
РС.ТипЦен.Код ЕСТЬ NULL
И НЕ РС.ТипЦен = ЗНАЧЕНИЕ(Справочник.ТипыЦенНоменклатуры.ПустаяСсылка)
Важное примечание: Обратите внимание на второе условие в секции ГДЕ. Если поле просто не заполнено (равно пустой ссылке справочника), то обращение к его реквизиту также вернет значение NULL. Чтобы исключить пустые ссылки из выборки и оставить исключительно "битые" значения, мы явно отсекаем пустую ссылку с помощью конструкции ЗНАЧЕНИЕ(...).
Также существует альтернативный вариант написания условия через проверку самой ссылки, который отлично работает на простых типах данных:
ВЫБРАТЬ
РС.ТипЦен КАК БитаяСсылка
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК РС
ГДЕ
РС.ТипЦен.Ссылка ЕСТЬ NULL
И НЕ РС.ТипЦен = ЗНАЧЕНИЕ(Справочник.ТипыЦенНоменклатуры.ПустаяСсылка)
Осторожно с составными типами данных! Если ваше поле имеет составной тип данных (например, поле может хранить ссылку как на справочник Контрагенты, так и на справочник ФизическиеЛица), конструкция Поле.Ссылка ЕСТЬ NULL может отрабатывать некорректно. В таких случаях рекомендуется выполнять явную проверку типов.
Еще один надежный способ найти "призраков" в базе данных — сравнить все имеющиеся в регистре значения со списком реально существующих элементов справочника. Сделать это можно с помощью отрицания условия вхождения в подзапрос:
ВЫБРАТЬ DISTINCT
РС.ТипЦен КАК БитаяСсылка
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК РС
ГДЕ
НЕ РС.ТипЦен В (ВЫБРАТЬ СправочникТаблица.Ссылка ИЗ Справочник.ТипыЦенНоменклатуры КАК СправочникТаблица)
И НЕ РС.ТипЦен = ЗНАЧЕНИЕ(Справочник.ТипыЦенНоменклатуры.ПустаяСсылка)
Разберем этот пример. Вложенный запрос выбирает абсолютно все реально существующие ссылки из справочника ТипыЦенНоменклатуры. Внешний запрос выбирает значения из регистра, которых нет в этом списке (и которые при этом не являются пустыми). Этот метод гарантирует стопроцентный результат, однако на таблицах объемом в миллионы записей он может работать медленнее, чем метод с обращением через точку к реквизиту.
Иногда требуется не просто вывести отчет по битым ссылкам, но и программно обработать каждую запись в цикле. Мы можем написать эффективную процедуру проверки.
Рассмотрим правильный современный способ проверки ссылок на существование с помощью метода ПолучитьОбъект(). Если объект базы данных удален, этот метод вернет системное значение Неопределено без вызова исключения.
Выборка = РегистрыСведений.ЦеныНоменклатуры.Выбрать();
Пока Выборка.Следующий() Цикл
СсылкаНаОбъект = Выборка.ТипЦен;
// Сначала проверяем, что ссылка в принципе заполнена
Если ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
// Попытка получить объект из базы данных
ОбъектБД = СсылкаНаОбъект.ПолучитьОбъект();
Если ОбъектБД = Неопределено Тогда
Сообщить("Внимание! Обнаружена битая ссылка в записи регистра: " + СсылкаНаОбъект);
// Здесь вы можете прописать логику очистки записи или её замены
КонецЕсли;
КонецЕсли;
КонецЦикла;
В старых версиях платформы или в некоторых конфигурациях разработчики использовали конструкцию Попытка ... Исключение для вызова метода ПолучитьОбъект(). Наша конструкция с проверкой на Неопределено работает значительно быстрее, так как не тратит ресурсы системы на генерацию и обработку системных исключений.
Если вам нужно проанализировать "битую" ссылку без обращения к базе данных, вы можете расшифровать информацию, которая содержится в скобках системного представления "Объект не найден...". Рассмотрим пример представления:
Объект не найден (84:b803001e6704040911e3b207df365313)
Внутри круглых скобок содержатся следующие технические данные:
84) — это внутренний идентификатор типа метаданных в вашей конкретной базе данных.b803001e6704040911e3b207df365313) — это уникальный идентификатор записи (UUID) в шестнадцатеричном формате.Используя внутренний идентификатор типа, программист может легко определить, к какому справочнику или документу принадлежал удаленный элемент, используя метод:
Метаданные.НайтиПоТипу()
Если ваша цель — не просто найти проблемные места, но и восстановить логическую структуру базы данных, воспользуйтесь стандартной утилитой платформы.
Разберем по шагам, как настроить эту процедуру:
Используйте этот инструмент с осторожностью. Как справедливо заметили участники обсуждения на форуме, запуск тестирования и исправления затронет абсолютно все таблицы информационной базы, что может быть нежелательно, если вам требуется точечная очистка конкретного регистра. Для такой задачи подойдёт обработка для удаления движений по битым ссылкам регистраторов.
В большинстве типовых конфигураций 1С имеется встроенная обработка "Поиск и замена значений" (ее также можно скачать отдельно с диска ИТС). Этот инструмент прекрасно подходит для точечной работы с поврежденными ссылками.
Проанализируем сценарий работы с ней:
В поле "Что заменять" вы можете скопировать битую ссылку. Поле "На что заменять" оставьте пустым (или укажите корректный элемент справочника). При нажатии кнопки поиска система выведет детальный список всех документов, регистров сведений и накопления, где используется данный "фантомный" уникальный идентификатор. Вы сможете точечно принять решение по каждому найденному совпадению.