Почему НайтиПоСсылкам возвращает пустой результат при указании массива исключаемых объектов?

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

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

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

Анализ синтаксиса и причин некорректного поведения

Разберем структуру параметров глобального метода НайтиПоСсылкам:

  1. Ссылки (обязательный) — массив искомых ссылок.
  2. ОбластьПоиска (необязательный) — массив разделителей данных. Если поиск ведется без учета разделителей, передается Неопределено или пустой массив.
  3. ВключитьОбъекты (необязательный) — массив объектов метаданных или их полных имен, среди которых производится поиск.
  4. ИсключитьОбъекты (необязательный) — массив объектов метаданных или их полных имен, которые необходимо пропустить при поиске.

Рассмотрим подробнее, почему попытка передать только массив исключений не срабатывает:

  1. Передача пустого массива во «ВключитьОбъекты»: если написать НайтиПоСсылкам(Ссылки, Новый Массив, Новый Массив, Исключить), платформа воспринимает второй массив буквально — множество разрешенных для поиска объектов метаданных является пустым. Соответственно, область поиска сужается до нуля, и результат всегда пуст.
  2. Пропуск параметра «ВключитьОбъекты»: если попытаться передать Неопределено в третий параметр или просто пропустить его запятыми (НайтиПоСсылкам(Ссылки, , , Исключить)), платформа на большинстве версий выдает системную ошибку Несоответствие типов (параметр номер 4). Механизм платформы не умеет рассчитывать исключения «от обратного» без явного задания базового множества поиска.
  3. Контекст прав доступа: метод НайтиПоСсылкам по умолчанию выполняется с проверкой прав текущего пользователя и RLS. Если у пользователя нет права Чтение хотя бы на одну сканируемую таблицу, вызов завершается аварийно.

Способ 1. Использование привилегированного режима (рекомендуемый)

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

Посмотрим на пример вызова на сервере:


УстановитьПривилегированныйРежим(Истина);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
УстановитьПривилегированныйРежим(Ложь);

Также эту процедуру можно вынести в общий серверный модуль с установленным флажком Привилегированный.

Способ 2. Явное заполнение массива включаемых объектов

Если бизнес-логика требует выполнить поиск исключительно в разрешенных метаданных или привилегированный режим недоступен по требованиям безопасности, разберем по шагам алгоритм с явным заполнением массива ВключитьОбъекты.

Для этого соберем все объекты конфигурации в массив включения за вычетом тех, которые мы хотим исключить, либо передадим оба массива в метод:


МассивИсключений = Новый Массив;
МассивИсключений.Добавить("РегистрСведений.БезопасноеХранилищеДанных");

МассивВключения = Новый Массив;
ДеревоМД = ОбщегоНазначения.ДеревоМетаданныхКонфигурации();

Для Каждого СтрокаКласса Из ДеревоМД.Строки Цикл
    Для Каждого СтрокаОбъекта Из СтрокаКласса.Строки Цикл
        МассивВключения.Добавить(СтрокаОбъекта.ПолноеИмя);
    КонецЦикла;
КонецЦикла;

ПустойМассивРазделителей = Новый Массив;
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок, ПустойМассивРазделителей, МассивВключения, МассивИсключений);

Если конфигурация разработана без использования Библиотеки Стандартных Подсистем (БСП), дерево метаданных можно обойти напрямую через коллекции объекта Метаданные (Справочники, Документы, РегистрыСведений и т. д.), проверяя для каждого объекта наличие прав через функцию ПравоДоступа("Чтение", ОбъектМетаданных).

Способ 3. Поиск ссылок прямым запросом

В сценариях, когда требуется проверить наличие ссылок не по всей конфигурации, а только в ключевых документах или регистрах, рекомендуется отказаться от сканирования всей базы в пользу точечного запроса. Это снижает нагрузку на СУБД и исключает проблемы с правами доступа.

Посмотрим на пример построения такого запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |   ДокументРеализация.Ссылка КАК Ссылка
    |ИЗ
    |   Документ.РеализацияТоваровУслуг КАК ДокументРеализация
    |ГДЕ
    |   ДокументРеализация.Контрагент В (&МассивСсылок)";

Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
РезультатЗапроса = Запрос.Выполнить();

Если Не РезультатЗапроса.Пустой() Тогда
    // Объект используется в документах реализации
КонецЕсли;

Резюме

При использовании метода НайтиПоСсылкам важно помнить, что параметр ИсключитьОбъекты не работает самостоятельно без полностью заполненного массива ВключитьОбъекты. Для устранения ошибок прав доступа оптимальным решением является выполнение поиска в привилегированном режиме на сервере.

← На главную