К статье
Практический материал

Администрирование · 11 мин

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

Как программно найти и удалить битые ссылки в 1С: проверка ПолучитьОбъект, обработка очистки ссылок, код для справочников, документов и регистров.

Битая ссылка в 1С — это ссылка на объект, которого уже нет в базе: элемент справочника, документ или запись были удалены, а ссылки на них остались в реквизитах других объектов, в табличных частях и в регистрах. В запросах такие ссылки отображаются как «Объект не найден» с длинным шестнадцатеричным идентификатором, а при попытке открыть их интерактивно платформа выдаёт ошибку.

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

Ниже разобраны способы определения битой ссылки в коде, готовые процедуры поиска по всем метаданным, варианты очистки и типичные ошибки, которые приводят к потере данных.

Что такое битая ссылка и откуда она берётся

Каждый объект ссылочного типа в 1С имеет уникальный идентификатор (GUID). Когда объект удаляется физически, а ссылки на него остаются, платформа не может материализовать объект по идентификатору — и возникает «битая» ссылка. Технически это значение с типом ссылки, у которого запрос к базе не возвращает ни одной записи.

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

Как определить битую ссылку в коде

Универсальный способ проверки — попытка получить объект по ссылке. Если объект физически отсутствует, метод ПолучитьОбъект() вернёт Неопределено. Дополнительно полезно проверять, что ссылка вообще заполнена, чтобы не путать пустое значение с битым.

Функция ЭтоБитаяСсылка(ПроверяемаяСсылка) Экспорт

Если Не ЗначениеЗаполнено(ПроверяемаяСсылка) Тогда

Возврат Ложь; // пустая ссылка — не битая

КонецЕсли;

Возврат ПроверяемаяСсылка.ПолучитьОбъект() = Неопределено;

КонецФункции

Для массовой проверки вызывать ПолучитьОбъект() в цикле дорого: каждый вызов — обращение к базе. Быстрее собрать ссылки в таблицу значений и проверить их одним запросом через левое соединение: если присоединённая таблица дала NULL, объекта нет.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Таб.Ссылка КАК Ссылка

|ПОМЕСТИТЬ ВТ_Ссылки

|ИЗ &ТаблицаСсылок КАК Таб

|;

|ВЫБРАТЬ

| ВТ_Ссылки.Ссылка КАК БитаяСсылка

|ИЗ ВТ_Ссылки КАК ВТ_Ссылки

| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Ном

| ПО ВТ_Ссылки.Ссылка = Ном.Ссылка

|ГДЕ Ном.Ссылка ЕСТЬ NULL";

Запрос.УстановитьПараметр("ТаблицаСсылок", ТаблицаСсылок);

Способ 1. Штатное удаление помеченных объектов

Прежде чем писать код, проверьте штатный механизм. В режиме «Удаление помеченных объектов» (в типовых конфигурациях — раздел «Администрирование») платформа при выборе варианта «Выборочное удаление» показывает все объекты, которые мешают удалению, и предлагает очистить ссылки на удаляемые объекты в найденных местах. Это самый безопасный путь: платформа сама знает все места использования.

Программно эту логику можно запустить через метод глобального контекста УдалитьПомеченныеОбъекты() в монопольном режиме. Метод удалит помеченные объекты, а в местах использования либо очистит ссылки, либо вернёт список препятствий, если удаление невозможно.

Порядок действий со штатным механизмом
  1. 1
    Сделайте резервную копию информационной базы
  2. 2
    Пометьте на удаление объекты, ссылки на которые стали битыми (если они ещё существуют)
  3. 3
    Запустите «Удаление помеченных объектов» в монопольном режиме
  4. 4
    Просмотрите список препятствий и обработайте проблемные места вручную
  5. 5
    Повторите удаление и проверьте отсутствие «Объект не найден» в отчётах

Способ 2. Поиск мест использования через НайтиПоСсылкам

Когда известна конкретная битая ссылка, все места её хранения находит метод НайтиПоСсылкам(). Он возвращает таблицу значений с колонками «Ссылка» (что искали), «Данные» (объект, где найдено) и «Метаданные» (где именно). Дальше по каждой строке принимается решение: очистить реквизит, удалить строку табличной части или удалить запись регистра.

МассивСсылок = Новый Массив;

МассивСсылок.Добавить(БитаяСсылка);

МестаИспользования = НайтиПоСсылкам(МассивСсылок);

Для Каждого Место Из МестаИспользования Цикл

ОбъектДанных = Место.Данные.ПолучитьОбъект();

// дальше — анализ, в каком реквизите сидит ссылка,

// и его очистка с последующей записью

КонецЦикла;

Ограничение метода — производительность: он сканирует все таблицы, где может встретиться ссылка данного типа. На больших базах запускайте поиск порциями и в нерабочее время.

Способ 3. Полный перебор метаданных и очистка реквизитов

Если битых ссылок много и их источники неизвестны, пишут универсальную обработку: перебираются справочники, документы и их реквизиты ссылочных типов, значения проверяются, битые очищаются. Ниже упрощённый каркас такой обработки для справочников.

Для Каждого МетаСпр Из Метаданные.Справочники Цикл

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Таб.Ссылка ИЗ Справочник."

+ МетаСпр.Имя + " КАК Таб";

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

Объект = Выборка.Ссылка.ПолучитьОбъект();

Изменён = Ложь;

Для Каждого Реквизит Из МетаСпр.Реквизиты Цикл

Значение = Объект[Реквизит.Имя];

Если ЗначениеЗаполнено(Значение)

И ЭтоСсылочныйТип(Значение)

И Значение.ПолучитьОбъект() = Неопределено Тогда

Объект[Реквизит.Имя] = Неопределено;

Изменён = Истина;

КонецЕсли;

КонецЦикла;

Если Изменён Тогда

Объект.ОбменДанными.Загрузка = Истина;

Объект.Записать();

КонецЕсли;

КонецЦикла;

КонецЦикла;

Функция ЭтоСсылочныйТип проверяет, что значение — ссылка, а не примитивный тип: проще всего через ТипЗнч() и сравнение с описанием типов реквизита, либо через попытку обращения к свойству ссылки. Обратите внимание на ОбменДанными.Загрузка = Истина — запись без проверок и бизнес-логики. Это ускоряет обработку, но отключает контроль, поэтому применяйте осознанно.

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

Проверка результата и тестирование целостности

После очистки убедитесь, что битых ссылок не осталось и не появились новые. Быстрый способ — построить универсальный отчёт или запрос по проблемным таблицам и проверить отсутствие значений вида «Объект не найден». Для файловых баз дополнительно выполните «Тестирование и исправление» (chdbfl для файловой базы или конфигуратор) с включённой проверкой ссылочной целостности — но только в режиме «Тестирование» без исправления, чтобы сначала увидеть список проблем.

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

Контрольные точки

Как проверить результат

Запрос по очищенным таблицам
Норма

Нет строк с «Объект не найден»

Тревожный признак

Ссылки с идентификатором остались

Открытие документов и отчётов
Норма

Формы открываются без ошибок

Тревожный признак

Ошибка «Объект не найден» при открытии

Тестирование и исправление
Норма

Проверка целостности без замечаний

Тревожный признак

Найдены ссылки на несуществующие объекты

Типичные ошибки при программной очистке

Самая частая ошибка — очистка ссылки вместо удаления строки там, где ссылка обязательна. Например, если в табличной части документа очистить колонку «Номенклатура», документ станет некорректным по смыслу; правильнее удалить строку или пометить документ на удаление. Вторая ошибка — обработка только реквизитов шапки и игнорирование табличных частей, регистров и последовательностей.

Третья группа ошибок — техническая: запуск обработки без монопольного режима (часть объектов не запишется из-за блокировок), отсутствие транзакции при пакетной записи и забытый ОбменДанными.Загрузка там, где он нужен, — или наоборот, его использование там, где нужна бизнес-логика записи.

Типичные ошибки
01
Очистка обязательной ссылки вместо удаления строки — объект остаётся, но становится бессмысленным
02
Игнорирование табличных частей и регистров сведений — половина битых ссылок остаётся
03
Запуск без монопольного режима и резервной копии — блокировки и невозможность отката
04
Вызов ПолучитьОбъект() в цикле по всей таблице — обработка большой базы идёт часами
05
Запись без ОбменДанными.Загрузка = Истина — срабатывают проверки и подписки, обработка падает

Частые вопросы

Чем битая ссылка отличается от пустой?

Пустая ссылка — это корректное значение «ничего не выбрано», она существует и равна пустой ссылке своего типа. Битая ссылка формально заполнена, но объекта с таким идентификатором в базе нет. Проверка ЗначениеЗаполнено() для битой ссылки вернёт Истина, поэтому отличать их нужно через ПолучитьОбъект() = Неопределено.

Можно ли восстановить объект по битой ссылке, а не удалять её?

Да, если известен GUID. Можно программно создать новый объект и установить ему ссылку с нужным идентификатором через Справочники.Имя.ПолучитьСсылку(Новый УникальныйИдентификатор("...")) и запись объекта по этой ссылке. Так делают, когда объект потерян при обмене, а ссылки на него ценны.

Почему «Удаление помеченных объектов» не удаляет объект?

Платформа показывает список мест, где объект используется, и блокирует удаление, если ссылки нельзя очистить автоматически — например, объект указан в измерении регистра или в критичном реквизите. Нужно выборочно разрешить очистку в найденных местах или обработать их вручную, после чего повторить удаление.

Опасно ли ставить ОбменДанными.Загрузка = Истина при записи?

Само по себе — нет, это стандартный приём для сервисных обработок. Опасность в том, что отключаются проверки заполнения, подписки на события и бизнес-логика: если ваша обработка ошибочно меняет данные, ничто её не остановит. Поэтому сначала делается прогон без записи, а запись включается после проверки списка изменений.

Как найти битые ссылки во всей базе сразу, а не по одному справочнику?

Пишется обработка с перебором коллекций метаданных: справочники, документы, планы видов характеристик, планы счетов, их реквизиты и табличные части, а также регистры сведений. Для каждого ссылочного поля выполняется запрос с левым соединением и условием IS NULL. Готовые универсальные обработки часто включают в состав инструментов администратора.

Нужно ли после очистки запускать «Тестирование и исправление»?

Желательно, но в режиме только проверки. Программная очистка правит данные на прикладном уровне, а «Тестирование и исправление» контролирует физическую целостность таблиц и индексов. Проверка подтвердит, что не осталось ссылок на несуществующие объекты и структура базы не повреждена.

Итог

Что важно запомнить

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