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