Как найти и исправить битые ссылки в справочнике Физические лица через внешнюю обработку

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

В процессе эксплуатации информационных баз 1С программисты часто сталкиваются с появлением «битых» ссылок. Это ситуации, когда в реквизите объекта хранится уникальный идентификатор (GUID), но сама запись, на которую он ссылается, была удалена из базы данных без контроля ссылочной целостности. В интерфейсе пользователя такие значения отображаются как «Объект не найден (84:...)». Разберем, как эффективно найти такие записи и корректно перезаписать их, чтобы восстановить целостность данных и при этом не затормозить работу системы.

Проблема поиска битых ссылок в запросе

Рассмотрим стандартную ситуацию: нам нужно отобрать элементы справочника ФизическиеЛица, у которых реквизит ГруппаДоступа содержит битую ссылку. Обычное сравнение с пустой ссылкой здесь не поможет, так как битая ссылка не является пустой — она содержит идентификатор, которого просто нет в таблице назначения.

Проанализируем наиболее эффективный способ решения этой задачи через механизм запросов. Когда мы обращаемся через точку к полю ссылочного типа, платформа 1С выполняет левое соединение (LEFT JOIN) с таблицей этого справочника. Если записи в целевой таблице нет, то результатом обращения к полям этой записи будет NULL.

Рассмотрим правильное условие для секции ГДЕ нашего запроса:


ГДЕ 
    ФизическиеЛица.ГруппаДоступа.Ссылка ЕСТЬ NULL 
    И НЕ ФизическиеЛица.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступаФизическихЛиц.ПустаяСсылка)

Разберем, почему это работает:

  1. ФизическиеЛица.ГруппаДоступа.Ссылка ЕСТЬ NULL — этот фрагмент кода заставляет платформу попытаться получить поле Ссылка из таблицы справочника ГруппыДоступаФизическихЛиц. Если ссылки в базе не существует, SQL-запрос вернет NULL.
  2. И НЕ ФизическиеЛица.ГруппаДоступа = ЗНАЧЕНИЕ(...) — это условие необходимо, чтобы исключить из выборки те записи, где ссылка действительно пустая (т.е. поле осознанно не заполнено пользователем). Пустая ссылка — это вполне легитимное значение, и она не является «битой».

Важно отметить, что использование конструкции ПРЕДСТАВЛЕНИЕ(ГруппаДоступа) ПОДОБНО "%Объект не найден%" крайне не рекомендуется. Во-первых, результат функции ПРЕДСТАВЛЕНИЕ зависит от языка сеанса пользователя. Во-вторых, это приводит к значительному замедлению выполнения запроса, так как СУБД приходится преобразовывать идентификаторы в строки для всех записей таблицы.

Оптимизация процесса записи объектов

В исходном коде автора наблюдалась проблема низкой производительности: обработка всего 100 записей занимала слишком много времени. Выясним причину такого поведения. По умолчанию при вызове метода Записать() платформа выполняет целый комплекс действий:

Для ускорения массовой очистки реквизитов мы должны использовать специальный флаг — режим загрузки данных. Установим свойство ОбменДанными.Загрузка в значение Истина. Это скажет платформе, что объект записывается «как есть», и большинство проверок и подписок на события можно пропустить. Это критически важно для производительности.

Реализация решения по шагам

Разберем теперь полный программный код внешней обработки, который решит поставленную задачу. Мы объединим правильный запрос и оптимизированный цикл обхода коллекции.


&НаСервере
Процедура ИсправитьБитыеСсылкиНаСервере()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ФизическиеЛица.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.ФизическиеЛица КАК ФизическиеЛица
        |ГДЕ
        |	ФизическиеЛица.ГруппаДоступа.Ссылка ЕСТЬ NULL
        |	И НЕ ФизическиеЛица.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступаФизическихЛиц.ПустаяСсылка)
        |	И ФизическиеЛица.ЭтоГруппа = ЛОЖЬ";
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        
        // Получаем объект для редактирования
        ОбъектФЛ = Выборка.Ссылка.ПолучитьОбъект();
        
        // Очищаем битую ссылку, устанавливая пустую ссылку справочника
        ОбъектФЛ.ГруппаДоступа = Справочники.ГруппыДоступаФизическихЛиц.ПустаяСсылка;
        
        // Включаем режим загрузки для ускорения и обхода проверок
        ОбъектФЛ.ОбменДанными.Загрузка = Истина;
        
        Попытка
            ОбъектФЛ.Записать();
            Сообщить("Исправлен объект: " + ОбъектФЛ.Наименование);
        Исключение
            ТекстОшибки = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
            Сообщить("Ошибка при записи объекта " + Выборка.Ссылка + ": " + ТекстОшибки);
        КонецПопытки;
        
    КонецЦикла;
    
    Сообщить("Обработка завершена.");
    
КонецПроцедуры

Проанализируем ситуацию, если использование ОбменДанными.Загрузка = Истина все равно не дает нужного ускорения. В этом случае стоит проверить, не настроены ли в базе активные планы обмена. Каждая запись объекта создает запись в системных таблицах регистрации изменений. Если вы уверены, что эти исправления не нужно передавать в другие базы (например, в бухгалтерию или филиалы), можно временно отключить регистрацию изменений для данного набора данных.

Использование стандартных средств (БСП)

Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), задачу можно решить еще проще, не прибегая к написанию программного кода. Посмотрим на алгоритм действий через типовую обработку «Групповое изменение реквизитов»:

  1. Откройте обработку Групповое изменение реквизитов (обычно находится в разделе Администрирование — Обслуживание — Корректировка данных).
  2. Выберите объект Физические лица.
  3. Нажмите гиперссылку «Все элементы» для настройки фильтра.
  4. Добавьте условие: Группа доступа.Ссылка — Не заполнено И Группа доступа — Заполнено. Этот фильтр как раз и отберет «битые» ссылки.
  5. В основной таблице выберите реквизит Группа доступа и установите ему значение «Пустая ссылка» (или просто оставьте пустым).
  6. В дополнительных параметрах (кнопка «Дополнительно») обязательно установите флажок «Записывать объекты в режиме загрузки».
  7. Нажмите «Изменить параметры».

Этот способ является наиболее безопасным и предпочтительным, так как механизмы БСП уже содержат все необходимые оптимизации для работы с большими массивами данных.

Почему появляются битые ссылки?

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

1. Удаление объектов без контроля целостности. Если программист или администратор использует метод Удалить() вместо УстановитьПометкуУдаления(), платформа физически стирает запись из таблицы базы данных, не проверяя, используется ли она в других местах.

2. Ошибки синхронизации. Если при обмене данными объект-владелец (например, Физлицо) пришел в базу, а связанный с ним объект (Группа доступа) по каким-то причинам был отфильтрован или не выгружен, в целевой базе образуется битая ссылка.

3. Прерывание транзакций при тестировании и исправлении (ТиИ). Если во время работы утилиты «Тестирование и исправление» происходит сбой, индексы могут быть нарушены, что приведет к ложному отображению объектов как найденных или не найденных.

Таким образом, мы выяснили, что для быстрого и качественного исправления данных необходимо сочетать точечный поиск через запрос с использованием ЕСТЬ NULL и скоростную запись с флагом ОбменДанными.Загрузка.

← На главную