При разработке механизмов проверки ссылочной целостности и удаления объектов в 1С разработчики часто сталкиваются с системной функцией НайтиПоСсылкам. Типичный сценарий — поиск мест использования помеченных на удаление элементов для пользователей с ограниченными правами. В таком случае сканирование закрытых регистров (например, РегистрыСведений.БезопасноеХранилищеДанных) вызывает ошибку нарушения прав доступа. Попытка исключить проблемный объект метаданных через штатный параметр метода нередко приводит к тому, что функция возвращает пустую таблицу ссылок, даже если ссылки в базе точно есть.
Проанализируем ситуацию, выясним внутреннюю логику работы метода и рассмотрим рабочие способы решения данной задачи.
Разберем структуру параметров глобального метода НайтиПоСсылкам:
Неопределено или пустой массив.Рассмотрим подробнее, почему попытка передать только массив исключений не срабатывает:
НайтиПоСсылкам(Ссылки, Новый Массив, Новый Массив, Исключить), платформа воспринимает второй массив буквально — множество разрешенных для поиска объектов метаданных является пустым. Соответственно, область поиска сужается до нуля, и результат всегда пуст.Неопределено в третий параметр или просто пропустить его запятыми (НайтиПоСсылкам(Ссылки, , , Исключить)), платформа на большинстве версий выдает системную ошибку Несоответствие типов (параметр номер 4). Механизм платформы не умеет рассчитывать исключения «от обратного» без явного задания базового множества поиска.НайтиПоСсылкам по умолчанию выполняется с проверкой прав текущего пользователя и RLS. Если у пользователя нет права Чтение хотя бы на одну сканируемую таблицу, вызов завершается аварийно.Если цель исключения объектов метаданных заключалась только в обходе системных таблиц, закрытых для пользователя (таких как служебные регистры БСП), правильнее всего выполнять поиск в привилегированном контексте. В привилегированном режиме проверки прав доступа и RLS отключаются, поэтому метод отрабатывает штатно по всей базе данных.
Посмотрим на пример вызова на сервере:
УстановитьПривилегированныйРежим(Истина);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
УстановитьПривилегированныйРежим(Ложь);
Также эту процедуру можно вынести в общий серверный модуль с установленным флажком Привилегированный.
Если бизнес-логика требует выполнить поиск исключительно в разрешенных метаданных или привилегированный режим недоступен по требованиям безопасности, разберем по шагам алгоритм с явным заполнением массива ВключитьОбъекты.
Для этого соберем все объекты конфигурации в массив включения за вычетом тех, которые мы хотим исключить, либо передадим оба массива в метод:
МассивИсключений = Новый Массив;
МассивИсключений.Добавить("РегистрСведений.БезопасноеХранилищеДанных");
МассивВключения = Новый Массив;
ДеревоМД = ОбщегоНазначения.ДеревоМетаданныхКонфигурации();
Для Каждого СтрокаКласса Из ДеревоМД.Строки Цикл
Для Каждого СтрокаОбъекта Из СтрокаКласса.Строки Цикл
МассивВключения.Добавить(СтрокаОбъекта.ПолноеИмя);
КонецЦикла;
КонецЦикла;
ПустойМассивРазделителей = Новый Массив;
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок, ПустойМассивРазделителей, МассивВключения, МассивИсключений);
Если конфигурация разработана без использования Библиотеки Стандартных Подсистем (БСП), дерево метаданных можно обойти напрямую через коллекции объекта Метаданные (Справочники, Документы, РегистрыСведений и т. д.), проверяя для каждого объекта наличие прав через функцию ПравоДоступа("Чтение", ОбъектМетаданных).
В сценариях, когда требуется проверить наличие ссылок не по всей конфигурации, а только в ключевых документах или регистрах, рекомендуется отказаться от сканирования всей базы в пользу точечного запроса. Это снижает нагрузку на СУБД и исключает проблемы с правами доступа.
Посмотрим на пример построения такого запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ДокументРеализация.Ссылка КАК Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК ДокументРеализация
|ГДЕ
| ДокументРеализация.Контрагент В (&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
// Объект используется в документах реализации
КонецЕсли;
При использовании метода НайтиПоСсылкам важно помнить, что параметр ИсключитьОбъекты не работает самостоятельно без полностью заполненного массива ВключитьОбъекты. Для устранения ошибок прав доступа оптимальным решением является выполнение поиска в привилегированном режиме на сервере.