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