Как настроить рекурсивный RLS для иерархии номенклатуры в 1С?

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

При настройке системы прав доступа (RLS — Record Level Security) часто возникает задача ограничить чтение элементов справочника Справочник.Номенклатура на основании разрешенных групп. При этом требуется, чтобы ограничение автоматически распространялось не только на прямых потомков указанной группы, но и на все подгруппы любой глубины вложенности.

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

Почему прямой рекурсивный запрос в RLS не работает

Проанализируем технические ограничения платформы 1С:Предприятие при работе с RLS:

  1. Отсутствие поддержки временных таблиц и рекурсивных CTE в тексте ограничения: Текст RLS транслируется платформой в подзапрос на уровне СУБД. Встроить полноценный рекурсивный обход дерева «на лету» внутри подзапроса к каждой строке невозможно.
  2. Неэффективность конструкции В ИЕРАРХИИ: Использование оператора В ИЕРАРХИИ внутри условий RLS со сложными подзапросами приводит к существенному падению производительности. На уровне СУБД это порождает множественные подзапросы и сканирование таблиц (Table Scan), что вызывает критические блокировки при параллельной работе пользователей.
  3. Требование к простоте RLS: Ограничения на уровне записей должны быть максимально легковесными, так как они неявно добавляются ко всем запросам к таблице (в динамических списках, отчетах, проведении документов).

Рассмотрим основные способы реализации доступа к иерархическим данным, исключающие тяжелые вычисления в момент выборки данных.

Способ 1. Предварительный расчет дерева в параметрах сеанса

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

Разберем реализацию по шагам:

  1. Создадим параметр сеанса ДоступныеГруппыНоменклатуры с типом ФиксированныйМассив.
  2. В модуле сеанса или в процедуре инициализации прав заполним массив всеми разрешенными группами, включая их рекурсивный обход.

Посмотрим на пример функции формирования массива разрешенных групп:


Функция ПолучитьМассивДоступныхГрупп(ТекущийПользователь)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Регистр.ГруппаНоменклатуры КАК Группа
        |ИЗ
        |   РегистрСведений.ДоступныеГруппыНоменклатурыПользователя КАК Регистр
        |ГДЕ
        |   Регистр.Пользователь = &ТекущийПользователь";
    
    Запрос.УстановитьПараметр("ТекущийПользователь", ТекущийПользователь);
    Выборка = Запрос.Выполнить().Выбрать();
    
    МассивГрупп = Новый Массив;
    
    Пока Выборка.Следующий() Цикл
        // Получаем все вложенные группы с помощью запроса с оператором В ИЕРАРХИИ
        ЗапросИерархии = Новый Запрос;
        ЗапросИерархии.Текст = 
            "ВЫБРАТЬ
            |   Номенклатура.Ссылка КАК Ссылка
            |ИЗ
            |   Справочник.Номенклатура КАК Номенклатура
            |ГДЕ
            |   Номенклатура.ЭтоГруппа = ИСТИНА
            |   И Номенклатура.Ссылка В ИЕРАРХИИ(&РодительскаяГруппа)";
        
        ЗапросИерархии.УстановитьПараметр("РодительскаяГруппа", Выборка.Группа);
        ВыборкаИерархии = ЗапросИерархии.Выполнить().Выбрать();
        
        Пока ВыборкаИерархии.Следующий() Цикл
            МассивГрупп.Добавить(ВыборкаИерархии.Ссылка);
        КонецЦикла;
    КонецЦикла;
    
    Возврат Новый ФиксированныйМассив(МассивГрупп);
    
КонецФункции

Текст ограничения RLS для справочника Номенклатура при этом становится предельно простым и быстрым:


ГДЕ Родитель В (&ДоступныеГруппыНоменклатуры)
   ИЛИ Ссылка В (&ДоступныеГруппыНоменклатуры)

Преимущество: Запрос RLS отрабатывает моментально без тяжелых соединений.
Ограничение: При добавлении новых вложенных папок в течение рабочего дня пользователю может потребоваться перезапуск сеанса для обновления массива в параметре сеанса.

Способ 2. Использование реквизита «Группа доступа» (денормализация)

В типовых конфигурациях 1С широко используется подход с денормализацией прав доступа с помощью специального реквизита.

Разберем механизм работы:

  1. В справочник Номенклатура добавляется реквизит ГруппаДоступа (ссылка на отдельный справочник ГруппыДоступаНоменклатуры).
  2. В обработчике ПередЗаписью объекта или в подписке на событие настраивается автоматическое наследование группы доступа: если создается новый элемент или группа, реквизит ГруппаДоступа автоматически копируется из вышестоящего родителя.
  3. Ограничение RLS настраивается не по иерархии родительских папок, а по простому равенству плоского реквизита:

Номенклатура 
ГДЕ Номенклатура.ГруппаДоступа В (&ДоступныеГруппыДоступаПользователя)

Такой подход устраняет необходимость рекурсивного анализа структуры при чтении данных и гарантирует моментальное применение прав ко всем созданным объектам.

Способ 3. Таблица транзитивного замыкания (вспомогательный регистр иерархии)

Если структура каталога меняется динамически, а перезапуск сеансов недопустим, классическим решением реляционных баз данных является использование вспомогательного регистра сведений (таблицы транзитивного замыкания).

Рассмотрим структуру регистра ИерархияНоменклатуры:

При записи любого элемента или группы номенклатуры в подписке на событие ПриЗаписи выполняется пересчет строк в регистре для измененного элемента и его потомков. В результате регистр содержит плоский список всех связей «Предок — Потомок».

Текст RLS в этом случае строится через быстрое соединение по индексированным измерениям:


Номенклатура
ГДЕ Номенклатура.Ссылка В
    (ВЫБРАТЬ
        Иерархия.Потомок
    ИЗ
        РегистрСведений.ИерархияНоменклатуры КАК Иерархия
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДоступныеГруппыНоменклатурыПользователя КАК ДоступныеГруппы
            ПО Иерархия.Родитель = ДоступныеГруппы.ГруппаНоменклатуры
    ГДЕ
        ДоступныеГруппы.Пользователь = &ТекущийПользователь)

Сводные рекомендации

Подведем итоги выбора архитектуры:

  1. Для небольших баз данных и стабильной структуры каталога оптимально использовать Параметры сеанса.
  2. Для высоконагруженных систем с развитой ролевой моделью рекомендуется внедрять Группы доступа (по аналогии с БСП) с наследованием при записи.
  3. Если требуется сохранять строгую динамическую иерархию без привязки к сеансам, используйте регистр транзитивного замыкания.
← На главную