Допускают ли шаблоны RLS в 1С вложенность и как это реализовать?

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

Механизм Record Level Security (RLS) в 1С:Предприятии часто требует написания объемных и повторяющихся условий. Программисты нередко задаются вопросом: можно ли создать иерархию шаблонов, где один шаблон вызывает другой? Это позволило бы централизовать логику управления правами доступа и избежать копирования одного и того же кода в десятки ролей и объектов метаданных.

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

Механизм работы шаблонов: текстовая подстановка

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

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

Пример кода базового шаблона #Доступ(ВидОбъекта, ПолеОбъекта):


(
#Параметр(2) В (
  ВЫБРАТЬ ЗначениеРеквизита ИЗ РегистрСведений.гпд_ДетальныеПрава КАК Т
  ГДЕ 
    Т.Пользователь = &ТекущийПользователь 
    И Т.ВидОбъекта = "#Параметр(1)" 
    И Т.РеквизитОбъекта = "#Параметр(2)" 
    И Т.Кроме = Ложь)
ИЛИ 
#Параметр(2) НЕ В (
  ВЫБРАТЬ ЗначениеРеквизита ИЗ РегистрСведений.гпд_ДетальныеПрава КАК Т
  ГДЕ 
    Т.Пользователь = &ТекущийПользователь 
    И Т.ВидОбъекта = "#Параметр(1)" 
    И Т.РеквизитОбъекта = "#Параметр(2)" 
    И Т.Кроме = Истина)
)

Реализация вложенности шаблонов

Теперь выясним, как вызвать этот шаблон из другого, более высокоуровневого шаблона. Допустим, мы хотим создать шаблон #ДоступВида(Вид), который будет автоматически применять ограничения ко всем необходимым полям конкретного типа документа (например, ЗаказПокупателя).

Проанализируем пример реализации такого вложенного шаблона:


#Если "#Параметр(1)" = "ЗаказПокупателя" #Тогда
    #Доступ("ЗаказПокупателя", "Организация")
    И #Доступ("ЗаказПокупателя", "Контрагент")
    И #Доступ("ЗаказПокупателя", "Ответственный")
    И #Доступ("ЗаказПокупателя", "Автор")
#КонецЕсли

Важный момент: Конфигуратор 1С может выдавать предупреждения или ошибки при попытке сохранения таких конструкций, так как синтаксический анализатор не всегда корректно разворачивает вложенные макросы в режиме редактирования. Однако, как показывает практика, в режиме 1С:Предприятие такие ограничения работают корректно, так как исполняющая среда успешно выполняет все текстовые подстановки перед выполнением SQL-запроса.

Использование «вставок» без ключевого слова ГДЕ

Рассмотрим еще один эффективный метод — использование шаблонов-вставок. Если мы хотим сделать структуру правил максимально прозрачной, мы можем разделять условия на части. Например, создать шаблон #Правило_СкладскиеДокументы, который внутри себя собирает условия из других шаблонов.

Пример шаблона #Правило_СкладскиеДокументы:


ГДЕ #Вставка_ВидимыеСклады И #Вставка_ОграничениеПоВидамТаблиц

А сами «вставки» (#Вставка_ВидимыеСклады) будут содержать только логику:


#Если НЕ &ОграничениеПоСкладам_Использовать #Тогда
    Истина
#Иначе
    Склад В (&ОграничениеПоСкладам_МножествоВидимых)
#КонецЕсли

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

Нюансы с кавычками и параметрами

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

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

ГДЕ #ДоступВида("""ЗаказПокупателя""")

Почему это необходимо? Препроцессор 1С при первой подстановке снимает один уровень кавычек. Чтобы в итоговый SQL-запрос значение попало именно как строка (в одинарных кавычках на уровне SQL или в двойных на уровне языка запросов 1С), необходимо «заэкранировать» их на уровне шаблона.

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

Несмотря на удобство вложенных шаблонов, проанализируем возможные риски:

  1. Лимиты СУБД по количеству таблиц: Каждый вложенный шаблон, содержащий подзапрос к регистру (ВЫБРАТЬ ... ИЗ РегистрСведений...), добавляет новые соединения (JOIN) или вложенные выборки в итоговый SQL-запрос. SQL Server имеет ограничение (обычно 256 таблиц в одном запросе). Если у вашего объекта 20 реквизитов и на каждый накладывается вложенный RLS с подзапросом, вы можете быстро достичь этого предела.
  2. Сложность отладки: Поскольку итоговый текст запроса формируется динамически, найти ошибку в синтаксисе вложенного шаблона крайне сложно. Для проверки рекомендуется использовать Технологический журнал или консоли запросов с включенной проверкой прав.
  3. Передача параметров: Прямая передача одного параметра шаблона в другой (например, #Шаблон1(#Параметр(1))) не всегда работает стабильно. Проанализируйте возможность использования глобальных имен параметров внутри цепочки вызовов.

Сравнение с БСП (Библиотека стандартных подсистем)

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

Подведем итог: вложенность шаблонов RLS в 1С возможна и является мощным инструментом для рефакторинга правил доступа. Используйте этот механизм для исключения дублирования кода, но всегда следите за итоговой сложностью генерируемого SQL-запроса, чтобы не допустить деградации производительности системы.

← На главную