Разработчики 1С часто сталкиваются с ситуацией, когда стандартный метод НайтиПоСсылкам возвращает список объектов (например, документов), но при ручном осмотре этих объектов или программном переборе их реквизитов и табличных частей искомая ссылка не обнаруживается. В этой статье мы подробно разберем, почему так происходит, где именно "прячутся" ссылки и как правильно диагностировать подобные случаи.
Проблема заключается в том, что метод НайтиПоСсылкам анализирует не только физические поля (реквизиты) конкретного объекта метаданных, но и всю ссылочную структуру базы данных на уровне СУБД. Когда мы передаем массив ссылок в эту функцию, платформа проверяет все возможные связи, прописанные в конфигурации. Рассмотрим стандартный вызов функции:
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(ИскомаяСсылка);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
Результатом работы метода является таблица значений с тремя основными колонками: Ссылка (что искали), Данные (где нашли — ссылка на объект-владелец) и Метаданные (описание конкретного поля, где найдена ссылка). Ошибка многих разработчиков заключается в том, что они смотрят только в колонку Данные, видят там ссылку на документ и пытаются найти значение в его реквизитах. Однако ссылка может находиться далеко за пределами свойств самого документа.
Проанализируем наиболее частую ситуацию: поиск указывает на документ, но в самом документе (его шапке или табличных частях) ссылки нет. В 90% случаев это означает, что ссылка содержится в регистрах, по которым этот документ сделал движения.
Когда документ проводится, он записывает данные в регистры накопления, сведений, расчета или бухгалтерии. В этих записях (движениях) поле Регистратор указывает на наш документ. Метод НайтиПоСсылкам находит запись в таблице регистра, видит, что она связана с документом-регистратором, и возвращает в колонке Данные именно ссылку на документ.
Рассмотрим, как это выглядит на практике. Если ссылка на номенклатуру удалена из табличной части документа, но движения по регистру "Запасы" не были очищены (например, из-за программной записи набора записей с установленным признаком ОбменДанными.Загрузка = Истина), то НайтиПоСсылкам будет упорно указывать на этот документ, так как в базе данных все еще существует запись регистра, ссылающаяся и на документ, и на номенклатуру.
Помимо движений по регистрам, ссылка может находиться в местах, которые не всегда очевидны при беглом анализе метаданных:
Метаданные().Реквизиты не включает такие поля, как Владелец, Родитель или Характеристика. Для их проверки нужно обращаться к коллекции СтандартныеРеквизиты.НайтиПоСсылкам часто игнорирует эти таблицы, но при определенных условиях (зависит от версии платформы) они могут влиять на результат.Чтобы не гадать, в каком именно поле "застряла" ссылка, необходимо анализировать колонку Метаданные из результата функции НайтиПоСсылкам. Рассмотрим пример кода, который поможет точно определить место:
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
Для Каждого СтрокаРезультата Из ТаблицаСсылок Цикл
// В колонке "Данные" находится объект, который держит ссылку (например, ДокументСсылка)
// В колонке "Метаданные" находится объект метаданных (например, Измерение регистра)
Сообщить("Найдено в объекте: " + Строка(СтрокаРезультата.Данные));
Сообщить("Тип метаданных: " + СтрокаРезультата.Метаданные.ПолноеИмя());
// Если это регистр, мы увидим что-то вроде:
// РегистрНакопления.ОстаткиТоваров.Измерение.Склад
КонецЦикла;
Если вы обнаружили, что ссылка находится в регистре, вы можете программно прочитать движения документа по этому конкретному регистру и убедиться в наличии связи:
// Пример анализа движений документа по конкретному регистру
НаборЗаписей = РегистрыНакопления.ОстаткиТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаНайденныйДокумент);
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
Если Запись.Склад = ИскомаяСсылка Тогда
Сообщить("Ссылка найдена в записи регистра накопления!");
КонецЕсли;
КонецЦикла;
Проанализируем пошагово, что нужно делать, если поиск выдает объект, но внутри его нет:
РегистрНакопления, РегистрСведений или другой регистр — значит, в самом документе искать нечего, нужно чистить движения.ЛюбаяСсылка или в строковом реквизите, который платформа ошибочно (или намеренно в старых версиях) индексировала как ссылочный.NULL или пустое значение, возможно, повреждены индексы таблиц. Выполните "Переиндексацию таблиц" и "Реиндексацию" в консоли администрирования или через конфигуратор.Важный момент: Помните, что метод НайтиПоСсылкам работает очень быстро, так как использует индексы СУБД. Если вы пытаетесь найти ссылки собственным перебором через Метаданные(), как делал автор исходного вопроса, это будет работать в десятки раз медленнее и может пропустить ссылки в регистрах, если вы не добавили их обход в свой алгоритм.
Таким образом, всегда доверяйте результату НайтиПоСсылкам, но учитесь правильно интерпретировать его отчет. Если система говорит, что ссылка в документе есть — значит, она есть либо в его "теле", либо в его "следах" (движениях), оставленных в базе данных.