Как программно найти и удалить битые ссылки в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Рассмотрим ситуацию, с которой сталкивается практически каждый разработчик 1С: в формах документов, справочниках или регистрах вместо нормального представления объекта отображается надпись <Объект не найден> и длинный набор символов. Проанализируем эту ситуацию и выясним причину возникновения проблемы, а затем разберем по шагам эффективные способы ее решения.

Выясним причину: откуда берутся битые ссылки?

Битая ссылка — это ситуация, когда в реквизите существующего объекта базы данных или в записи регистра хранится уникальный идентификатор (GUID) объекта, которого физически больше нет в таблицах базы. Выясним причину их появления. Чаще всего это происходит по нескольким причинам:

  1. Непосредственное удаление: Пользователь с полными правами удалил объект комбинацией клавиш Shift + Delete, обойдя стандартный механизм пометки на удаление и контроля ссылочной целостности. Чтобы полностью стереть сведения по отдельной организации без нарушения контроля ссылочной целостности, применяется обработка для выборочного удаления организаций в 1С.
  2. Сбои при обменах данными: В распределенных информационных базах (РИБ) или при синхронизации документ может прийти в базу со ссылкой на справочник, но сам элемент справочника по какой-то причине не загрузился или был удален в главном узле. Для своевременного обнаружения расхождений в учете, вызванных сбоями при обмене или переносе данных, применяется программа для автоматической сверки проводок между базами 1С.
  3. Технические сбои: Отключение питания серверов, некорректное завершение транзакций на уровне СУБД или повреждение таблиц базы данных.

Анализ частой ошибки при поиске битых ссылок запросом

Проанализируем ситуацию, в которую часто попадают начинающие разработчики. При попытке найти битую ссылку программно разработчики пишут запрос напрямую к таблице того объекта, который был удален. Посмотрим на пример некорректного кода, который мы встретили в обсуждении:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ПоступлениеНаРасчетныйСчет.Ссылка КАК Ссылка
    |ИЗ
    |    Документ.ПоступлениеНаРасчетныйСчет КАК ПоступлениеНаРасчетныйСчет
    |ГДЕ
    |    ПоступлениеНаРасчетныйСчет.Ссылка ЕСТЬ NULL";
РезультатЗапроса = Запрос.Выполнить();

Этот код никогда ничего не найдет. Причина проста: если запись была удалена из таблицы Документ.ПоступлениеНаРасчетныйСчет, платформа 1С просто не вернет из нее данные. Запрос обращается к пустоте. Битая ссылка хранится не в таблице удаленного объекта, а в таблице другого объекта, который на него ссылался.

Рассмотрим подробнее: как правильно найти битые ссылки запросом

Чтобы правильно найти объекты, содержащие битые ссылки, необходимо обращаться к таблицам тех справочников или документов, где эти ссылки «застряли» в реквизитах. Разберем по шагам правильное условие для запроса:

  1. Обращаемся к нужной таблице, например Справочник.Номенклатура.
  2. Проверяем реквизит, в котором может храниться битая ссылка, через разыменование поля (через точку), проверяя поле Ссылка на значение NULL.
  3. Обязательно отсекаем пустые ссылки, так как пустая ссылка при обращении через точку тоже вернет NULL.

Посмотрим на пример правильного условия запроса:


ГДЕ Объект.РеквизитОбъекта.Ссылка ЕСТЬ NULL 
И НЕ Объект.РеквизитОбъекта = &ПустаяСсылка

Программная проверка ссылок без использования запросов

Рассмотрим еще один метод. Если у нас в коде уже есть переменная со ссылкой, и нам нужно определить, "живая" она или битая, мы можем использовать метод ПолучитьОбъект(). Посмотрим на пример кода:


Если Ссылка.ПолучитьОбъект() = Неопределено Тогда
    // Объект не найден в базе данных, ссылка битая
    Сообщить("Найдена битая ссылка!");
КонецЕсли;

Этот способ крайне прост и надежен, однако мы не рекомендуем использовать его в массовых циклах обработки данных, так как метод ПолучитьОбъект() считывает все данные объекта в оперативную память, что при большом объеме может сильно замедлить работу системы. Для массовых операций всегда используйте язык запросов 1С.

Разберем по шагам очистку ссылок в справочниках и документах

Перейдем к практическому решению. Предположим, у нас есть справочник Номенклатура, в реквизите которого Реквизит1 застряла битая ссылка. Нам нужно очистить этот реквизит программно. Посмотрим на пример рабочего скрипта:


Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ 
    |    Ссылка 
    |ИЗ 
    |    Справочник.Номенклатура 
    |ГДЕ 
    |    Реквизит1.Ссылка ЕСТЬ NULL
    |    И Реквизит1 <> ЗНАЧЕНИЕ(Справочник.ИмяСправочника.ПустаяСсылка)";
 
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    НомОбъект = Выборка.Ссылка.ПолучитьОбъект();
    // Очищаем реквизит
    НомОбъект.Реквизит1 = Неопределено; 
    // Отключаем бизнес-логику при записи для ускорения
    НомОбъект.ОбменДанными.Загрузка = Истина;
    НомОбъект.Записать();
КонецЦикла;

Использование свойства ОбменДанными.Загрузка = Истина позволяет обойти проверки в модуле объекта при записи, что критически важно для массовых обработок.

Рассмотрим подробнее очистку битых ссылок в регистрах

Чаще всего осиротевшие ссылки остаются именно в регистрах (накопления, сведений или бухгалтерии), когда документ-регистратор был физически удален, а его движения остались в базе. В таком случае в интерфейсе в колонке "Регистратор" мы видим "Объект не найден". Разберем по шагам алгоритм их удаления программно:

  1. Формируем запрос к нужной виртуальной или физической таблице регистра.
  2. Отбираем записи с условием ГДЕ Регистратор.Ссылка ЕСТЬ NULL.
  3. В цикле создаем новый НаборЗаписей.
  4. Устанавливаем отбор по битому регистратору.
  5. Вызываем метод Записать() без параметров (тем самым мы записываем пустой набор записей и затираем "мусор").

Посмотрим на пример реализации:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    РегистрНакопленияТоварыНаСкладах.Регистратор КАК Регистратор
    |ИЗ
    |    РегистрНакопления.ТоварыНаСкладах КАК РегистрНакопленияТоварыНаСкладах
    |ГДЕ
    |    РегистрНакопленияТоварыНаСкладах.Регистратор.Ссылка ЕСТЬ NULL";

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Регистратор.Установить(Выборка.Регистратор);
    // Записываем пустой набор, стирая движения битого регистратора
    НаборЗаписей.Записать(); 
КонецЦикла;

Посмотрим на пример восстановления объекта по GUID

Что делать, если удаление реквизита нежелательно, и данные нужно сохранить? Мы можем не очищать ссылку, а программно восстановить сам удаленный объект. В строке "Объект не найден" 1С отображает уникальный идентификатор (например: 84:bf5600145e3710ab11dda4c605dbe824). Мы можем извлечь этот GUID, привести его к стандартному строковому формату 1С и создать "объект-заглушку". Рассмотрим подробнее, как это сделать программно:


// СтрокаGUID - это заранее извлеченный стандартный идентификатор
НовыйИД = Новый УникальныйИдентификатор(СтрокаGUID);
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(НовыйИД);

НовыйОбъект = Справочники.Контрагенты.СоздатьЭлемент();
// Принудительно устанавливаем ту самую битую ссылку
НовыйОбъект.УстановитьСсылку(НоваяСсылка);
НовыйОбъект.Наименование = "Восстановленный контрагент (Заглушка)";
НовыйОбъект.Записать();

После выполнения этого кода во всех документах и регистрах, где раньше была пугающая надпись о ненайденном объекте, автоматически появится наш "Восстановленный контрагент". Пользователи или аналитики смогут затем зайти в этот элемент и дозаполнить его корректными реквизитами. Для автоматизации этого процесса подойдёт обработка для поиска битых ссылок и создания объектов-заглушек.

Штатные средства: Тестирование и исправление (ТИИ)

Если мы не хотим писать код, мы можем использовать стандартный встроенный функционал платформы 1С. Проанализируем возможности утилиты "Тестирование и исправление". Она запускается в режиме Конфигуратора меню "Администрирование -> Тестирование и исправление". Для автоматического запуска этой проверки по расписанию одновременно в нескольких информационных базах применяется программа для пакетного тестирования и обслуживания баз 1С.

Чтобы система сама нашла и обработала битые ссылки, необходимо установить флаг "Проверка ссылочной целостности". Платформа предложит на выбор три варианта поведения:

  1. Очищать ссылки: Система пройдет по всем таблицам и заменит битые ссылки на пустые значения автоматически.
  2. Создавать объекты: Платформа сгенерирует пустые объекты с системными пометками вместо битых ссылок (аналог нашего программного восстановления).
  3. Удалять объект: Крайне опасный режим. Если платформа найдет битую ссылку в табличной части важного документа, она может удалить весь этот документ целиком. Используйте этот режим с огромной осторожностью и только после полного резервного копирования!

Подводя итог, мы выяснили причину возникновения битых ссылок, разобрали основные ошибки при работе с запросами, а также изучили несколько программных методов по их удалению и восстановлению. Внимательно выбирайте инструмент под ваши конкретные задачи и никогда не забывайте делать бэкапы баз данных перед запуском любых корректирующих обработок!

← На главную