При работе с платформой «1С:Предприятие» разработчики часто сталкиваются со странным поведением стандартной функции НайтиПоСсылкам(). Ситуация, когда система сообщает, что документ ссылается на самого себя, может вызвать недоумение, особенно если у объекта нет явных движений по регистрам и отсутствуют реквизиты соответствующего типа. Разберем детально, почему это происходит, как проанализировать скрытые связи и можно ли безопасно удалять такие объекты.
Прежде всего, проанализируем, как работает функция НайтиПоСсылкам(). Платформа не просто просматривает метаданные, которые мы видим в конфигураторе. Она выполняет прямой запрос к таблицам базы данных (СУБД), сканируя все поля всех таблиц, которые могут содержать тип данного объекта. Если в какой-то таблице (даже системной или скрытой) обнаруживается GUID нашего документа, функция включает эту запись в результат поиска.
Рассмотрим стандартный пример вызова функции:
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(СсылкаНаДокумент);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
Для Каждого СтрокаСсылки Из ТаблицаСсылок Цикл
Сообщить("Объект: " + СтрокаСсылки.Данные + " ссылается на: " + СтрокаСсылки.Ссылка);
КонецЦикла;
Если в колонке Данные оказывается тот же самый документ, что и в колонке Ссылка, мы имеем дело с «самоссылкой».
Выясним причину, связанную с Библиотекой стандартных подсистем (БСП). Одной из самых распространенных причин является включенное версионирование объектов. Механизм работает следующим образом: при записи документа создается запись в регистре сведений ВерсииОбъектов. В этом регистре хранятся данные о состоянии объекта в виде двоичных данных (XML или Fast Infoset).
Несмотря на то что ссылка в регистре ведет на документ, внутри сериализованных данных версии может храниться ссылка на этот же объект. Кроме того, при программном анализе через НайтиПоСсылкам() система может обнаруживать связи в измерениях регистра, где хранится ссылка на объект-владелец версии. Если документ был записан хотя бы один раз с включенным версионированием, «самоссылка» может отображаться как связь с данными версии.
Проанализируем структуру самого документа. Часто разработчики проверяют только реквизиты шапки с явным типом «ДокументСсылка.ИмяДокумента». Однако ссылка может скрываться в более глубоких слоях:
Чтобы найти такое поле, можно воспользоваться простым перебором метаданных:
ОбъектДок = СсылкаНаДокумент.ПолучитьОбъект();
Для Каждого Реквизит Из ОбъектДок.Метаданные().Реквизиты Цикл
Если ОбъектДок[Реквизит.Имя] = СсылкаНаДокумент Тогда
Сообщить("Найдена ссылка в реквизите: " + Реквизит.Имя);
КонецЕсли;
КонецЦикла;
Разберем ситуацию с Критериями отбора. В конфигурации часто создаются критерии типа «СвязанныеДокументы». Если в состав критерия включен ваш тип документа и какой-либо из его реквизитов (например, «Основание»), то при поиске ссылок система обращается к индексу критерия отбора. Если документ указан в качестве собственного основания, критерий зафиксирует эту связь как циклическую.
Рассмотрим механизмы синхронизации данных. Если документ участвует в обмене данными, он регистрируется на узлах планов обмена. Записи о регистрации изменений хранятся в специальных системных таблицах (таблицы регистрации). В некоторых случаях, особенно при использовании распределенных информационных баз (РИБ), наличие записи о регистрации объекта может интерпретироваться механизмом контроля целостности как наличие ссылки на объект. Хотя технически это не реквизит документа, это «живая» запись в базе данных, содержащая GUID объекта.
Посмотрим на связь с бизнес-логикой. Если документ является ведущим объектом для бизнес-процесса, платформа создает жесткую связь. В некоторых конфигурациях логика построена так, что задача или бизнес-процесс создаются «на основании» документа, а сам документ в своих скрытых системных полях (например, связанных с состоянием процесса) может хранить обратную ссылку. В этом случае НайтиПоСсылкам() может показать документ в контексте его участия в процессе.
Выясним техническую причину, связанную с состоянием СУБД. Иногда «самоссылка» — это не реальная связь в метаданных, а результат **повреждения индексов** или таблиц базы данных. Это случается при аварийном завершении работы сервера или сбоях в файловой системе. В таблице ссылок БД (или в индексах) остается «фантомная» запись, указывающая на объект.
Для решения этой проблемы необходимо выполнить процедуру **Тестирования и исправления (ТиИ)**:
Проанализируем риски при удалении объекта с самоссылкой. Ответ зависит от способа удаления:
1. Непосредственное удаление в коде
Метод Объект.Удалить() полностью игнорирует проверку ссылочной целостности. Если вы уверены, что документ лишний, вы можете удалить его программно. Наличие самоссылки не помешает этой операции.
2. Интерактивное удаление (через пометку удаления)
Стандартная обработка «Удаление помеченных объектов» выполняет проверку через ту же функцию НайтиПоСсылкам(). Если она увидит, что документ ссылается сам на себя, она может посчитать его «используемым» и отказаться удалять. В этом случае придется либо использовать программное удаление, либо предварительно очистить реквизит, содержащий самоссылку (если это реквизит документа).
Безопасность: Если анализ показал, что ссылка находится внутри самого объекта (в реквизите или ТЧ), удаление абсолютно безопасно для системы. Если же это признак повреждения БД, обязательно выполните «ТиИ» перед удалением, чтобы избежать проблем с целостностью всей базы в будущем.
Подведем итог. Если вы обнаружили, что документ ссылается сам на себя, выполните следующие действия:
Помните, что НайтиПоСсылкам() — это мощный инструмент, который иногда показывает нам внутреннюю «кухню» платформы, скрытую за интерфейсом конфигуратора.