Почему НайтиПоСсылкам находит объекты, в которых нет искомой ссылки?

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

Разработчики 1С часто сталкиваются с ситуацией, когда стандартный метод НайтиПоСсылкам возвращает список объектов (например, документов), но при ручном осмотре этих объектов или программном переборе их реквизитов и табличных частей искомая ссылка не обнаруживается. В этой статье мы подробно разберем, почему так происходит, где именно "прячутся" ссылки и как правильно диагностировать подобные случаи.

Суть проблемы и механизм работы метода

Проблема заключается в том, что метод НайтиПоСсылкам анализирует не только физические поля (реквизиты) конкретного объекта метаданных, но и всю ссылочную структуру базы данных на уровне СУБД. Когда мы передаем массив ссылок в эту функцию, платформа проверяет все возможные связи, прописанные в конфигурации. Рассмотрим стандартный вызов функции:


МассивСсылок = Новый Массив;
МассивСсылок.Добавить(ИскомаяСсылка);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);

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

Основная причина: Движения документа в регистрах

Проанализируем наиболее частую ситуацию: поиск указывает на документ, но в самом документе (его шапке или табличных частях) ссылки нет. В 90% случаев это означает, что ссылка содержится в регистрах, по которым этот документ сделал движения.

Когда документ проводится, он записывает данные в регистры накопления, сведений, расчета или бухгалтерии. В этих записях (движениях) поле Регистратор указывает на наш документ. Метод НайтиПоСсылкам находит запись в таблице регистра, видит, что она связана с документом-регистратором, и возвращает в колонке Данные именно ссылку на документ.

Рассмотрим, как это выглядит на практике. Если ссылка на номенклатуру удалена из табличной части документа, но движения по регистру "Запасы" не были очищены (например, из-за программной записи набора записей с установленным признаком ОбменДанными.Загрузка = Истина), то НайтиПоСсылкам будет упорно указывать на этот документ, так как в базе данных все еще существует запись регистра, ссылающаяся и на документ, и на номенклатуру.

Скрытые места нахождения ссылок

Помимо движений по регистрам, ссылка может находиться в местах, которые не всегда очевидны при беглом анализе метаданных:

  1. Стандартные реквизиты: Программный перебор через Метаданные().Реквизиты не включает такие поля, как Владелец, Родитель или Характеристика. Для их проверки нужно обращаться к коллекции СтандартныеРеквизиты.
  2. Планы обмена: Объект может быть зарегистрирован к выгрузке в одном или нескольких узлах планов обмена. Ссылка на него хранится в специальных таблицах регистрации изменений. Метод НайтиПоСсылкам часто игнорирует эти таблицы, но при определенных условиях (зависит от версии платформы) они могут влиять на результат.
  3. Последовательности документов: Если документ входит в последовательность и один из реквизитов последовательности (измерения) содержит искомую ссылку, поиск укажет на документ.
  4. Задачи и бизнес-процессы: Ссылка может быть связана с ведущим объектом задачи или реквизитами адресации, которые не видны в экранных формах.
  5. Кэш и индексы (фантомные ссылки): В крайне редких случаях при нарушении логической целостности базы данных в индексах таблиц может остаться "мусорная" запись. В таких ситуациях помогает процедура "Тестирование и исправление" (ТиИ).

Как правильно искать местонахождение ссылки программно

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


ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);

Для Каждого СтрокаРезультата Из ТаблицаСсылок Цикл
    // В колонке "Данные" находится объект, который держит ссылку (например, ДокументСсылка)
    // В колонке "Метаданные" находится объект метаданных (например, Измерение регистра)
    
    Сообщить("Найдено в объекте: " + Строка(СтрокаРезультата.Данные));
    Сообщить("Тип метаданных: " + СтрокаРезультата.Метаданные.ПолноеИмя());
    
    // Если это регистр, мы увидим что-то вроде:
    // РегистрНакопления.ОстаткиТоваров.Измерение.Склад
КонецЦикла;

Если вы обнаружили, что ссылка находится в регистре, вы можете программно прочитать движения документа по этому конкретному регистру и убедиться в наличии связи:


// Пример анализа движений документа по конкретному регистру
НаборЗаписей = РегистрыНакопления.ОстаткиТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаНайденныйДокумент);
НаборЗаписей.Прочитать();

Для Каждого Запись Из НаборЗаписей Цикл
    Если Запись.Склад = ИскомаяСсылка Тогда
        Сообщить("Ссылка найдена в записи регистра накопления!");
    КонецЕсли;
КонецЦикла;

Алгоритм действий при обнаружении "невидимых" ссылок

Проанализируем пошагово, что нужно делать, если поиск выдает объект, но внутри его нет:

  1. Проверьте колонку "Метаданные" в результате поиска. Это самый быстрый способ. Если там указан РегистрНакопления, РегистрСведений или другой регистр — значит, в самом документе искать нечего, нужно чистить движения.
  2. Выполните запрос к таблицам движений. Иногда визуально в форме списка движений записи могут быть скрыты фильтрами или особенностями интерфейса. Прямой запрос к таблице регистра с отбором по регистратору и искомому значению даст 100% результат.
  3. Проверьте составные типы данных. Ссылка может находиться в реквизите с типом ЛюбаяСсылка или в строковом реквизите, который платформа ошибочно (или намеренно в старых версиях) индексировала как ссылочный.
  4. Тестирование и исправление. Если программный поиск по метаданным из пункта 1 указывает на реквизит документа, а запрос показывает NULL или пустое значение, возможно, повреждены индексы таблиц. Выполните "Переиндексацию таблиц" и "Реиндексацию" в консоли администрирования или через конфигуратор.

Важный момент: Помните, что метод НайтиПоСсылкам работает очень быстро, так как использует индексы СУБД. Если вы пытаетесь найти ссылки собственным перебором через Метаданные(), как делал автор исходного вопроса, это будет работать в десятки раз медленнее и может пропустить ссылки в регистрах, если вы не добавили их обход в свой алгоритм.

Таким образом, всегда доверяйте результату НайтиПоСсылкам, но учитесь правильно интерпретировать его отчет. Если система говорит, что ссылка в документе есть — значит, она есть либо в его "теле", либо в его "следах" (движениях), оставленных в базе данных.

← На главную