При настройке ограничений прав доступа на уровне записей (RLS) в «1С:Документооборот» и других типовых конфигурациях часто возникает задача: предоставить руководителю доступ к документам всех его подчиненных, включая подчиненных через несколько уровней иерархии подразделений. Попытка решить эту задачу прямым перебором родителей через точку приводит к ошибкам и резкому падению производительности. Разберем, почему возникает эта проблема и как правильно ее решить.
Проанализируем исходный код условия RLS, в котором предпринята попытка подняться вверх по структуре подразделений:
#Если &ДокументооборотИспользоватьОграниченияПравДоступа #Тогда
ТаблицаДокумента ИЗ Документ.Отсутствие КАК ТаблицаДокумента
ГДЕ
ТаблицаДокумента.Сотрудник = &ТекущийПользователь ИЛИ
ТаблицаДокумента.Сотрудник.Подразделение.Руководитель = &ТекущийПользователь ИЛИ
ТаблицаДокумента.Сотрудник.Подразделение.Родитель.Руководитель = &ТекущийПользователь ИЛИ
ТаблицаДокумента.Сотрудник.Подразделение.Родитель.Руководитель.Подразделение.Родитель.Руководитель = &ТекущийПользователь
#КонецЕсли
Такой подход имеет принципиальные недостатки:
WITH RECURSIVE). Выбрать произвольное, заранее неизвестное количество уровней иерархии вверх одним выражением в запросе невозможно.Сотрудник.Подразделение.Родитель.Руководитель) транслируются СУБД в каскады неявных левых соединений (LEFT JOIN). Поскольку условие RLS накладывается на каждую считываемую строку, такой запрос быстро приводит к блокировкам таблиц и зависанию динамических списков.Оператор платформы В ИЕРАРХИИ отлично оптимизирован для проверки вхождения элементов сверху вниз, но не работает в обратную сторону. Поэтому вместо того, чтобы от документа подниматься вверх к руководителю, логику разворачивают в противоположном направлении.
Разберем по шагам, как это реализовать:
&ПодразделенияТекущегоРуководителя.В ИЕРАРХИИ:
#Если &ДокументооборотИспользоватьОграниченияПравДоступа #Тогда
ТаблицаДокумента ИЗ Документ.Отсутствие КАК ТаблицаДокумента
ГДЕ
ТаблицаДокумента.Сотрудник = &ТекущийПользователь
ИЛИ ТаблицаДокумента.Сотрудник.Подразделение В ИЕРАРХИИ (&ПодразделенияТекущегоРуководителя)
#КонецЕсли
В этом случае платформа использует внутренние индексы иерархии справочника, и проверка выполняется быстро независимо от глубины вложенности подразделений.
Если требуется предоставить доступ по сложной матрице подчинения (с учетом функциональных руководителей, замещений и рабочих групп), оптимальным решением является предварительный расчет прав при входе пользователя в систему.
Посмотрим на алгоритм реализации:
СписокДоступныхСотрудников с типом ФиксированныйМассив.
ТаблицаДокумента ИЗ Документ.Отсутствие КАК ТаблицаДокумента
ГДЕ
ТаблицаДокумента.Сотрудник В (&СписокДоступныхСотрудников)
Если состав подразделений и сотрудников часто меняется и хранить список в сеансе нецелесообразно, применяют подход с транзитивным замыканием структуры через непериодический регистр сведений.
Разберем архитектуру такого решения:
ИерархияПодразделенийИРуководителей с измерениями Подразделение, ВышестоящееПодразделение и Руководитель.ПриЗаписи справочника СтруктураПредприятия или Подразделения запускаем процедуру, которая программно раскручивает всех родителей каждого подразделения и записывает полные плоские связки со всеми вышестоящими руководителями.
ТаблицаДокумента ИЗ Документ.Отсутствие КАК ТаблицаДокумента
ГДЕ
ТаблицаДокумента.Сотрудник = &ТекущийПользователь
ИЛИ ТаблицаДокумента.Сотрудник.Подразделение В (
ВЫБРАТЬ
РегистрИерархии.Подразделение
ИЗ
РегистрСведений.ИерархияПодразделенийИРуководителей КАК РегистрИерархии
ГДЕ
РегистрИерархии.Руководитель = &ТекущийПользователь
)
Такой подход полностью исключает разыменование полей через точку, использует индексированные поля регистра и масштабируется на любую глубину организационной структуры компании.