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