Как в запросе 1С отфильтровать записи «Объект не найден», возникающие из-за ограничений RLS?

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

При работе в конфигурациях с включенным механизмом RLS (Row Level Security) программисты часто сталкиваются с ситуацией, когда результат запроса содержит записи со ссылками, отображаемыми как «Объект не найден». Это происходит в тех случаях, когда пользователю разрешено чтение основного объекта (например, документа), но запрещено чтение объекта, на который ссылается один из его реквизитов (например, справочник Контрагенты). В интерфейсе и в результатах запроса ВЫБРАТЬ РАЗРЕШЕННЫЕ такая ссылка превращается в «битую».

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

Почему появляются «Объекты не найдены» при использовании РАЗРЕШЕННЫЕ

Разберем ситуацию: в запросе используется ключевое слово РАЗРЕШЕННЫЕ. Платформа 1С автоматически модифицирует этот запрос, добавляя условия из настроек RLS. Если ограничение на документ настроено по «прочим полям» (например, по организации), то сам документ попадает в выборку. Однако, если на справочник, указанный в реквизите этого документа, у пользователя нет прав на чтение конкретной записи, платформа возвращает только идентификатор (GUID), но запрещает получение данных из таблицы справочника. В результате мы получаем ссылку, которая не может быть разрешена в объект.

Способ 1. Фильтрация через обращение к реквизиту (метод через точку)

Один из самых простых и быстрых способов — проверить наличие любого обязательного реквизита связанного объекта (например, Код или Наименование). Если у пользователя нет прав на чтение контрагента, то при попытке обратиться к его коду через точку, SQL-сервер вернет NULL.

Проанализируем пример кода, который позволяет быстро отфильтровать недоступные записи:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    ПоступлениеИнформации.Организация КАК Организация,
    ПоступлениеИнформации.Подразделение КАК Подразделение,
    ПоступлениеИнформации.Контрагент КАК Контрагент
ИЗ
    Документ.ПоступлениеИнформации КАК ПоступлениеИнформации
ГДЕ
    НЕ ПоступлениеИнформации.Контрагент.Код ЕСТЬ NULL

Важный нюанс: при таком подходе будут отсечены и те документы, где поле Контрагент просто не заполнено (пустая ссылка). Если нам нужно оставить пустые ссылки, но убрать именно «запрещенные» объекты, условие нужно усложнить.

Способ 2. Внутреннее соединение со справочником

Рассмотрим более надежный с точки зрения производительности SQL вариант. Использование ВНУТРЕННЕГО СОЕДИНЕНИЯ с таблицей справочника, к которому применяется RLS, автоматически исключит из итоговой выборки те записи, на чтение которых у пользователя нет прав. Поскольку 1С применит ограничения и к таблице документа, и к таблице справочника, в результат попадут только пересечения доступных данных.

Выясним, как это выглядит в коде:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Док.Организация КАК Организация,
    Док.Подразделение КАК Подразделение,
    Док.Контрагент КАК Контрагент
ИЗ
    Документ.ПоступлениеИнформации КАК Док
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК К
        ПО Док.Контрагент = К.Ссылка

Этот метод считается наиболее «чистым», так как оптимизатор СУБД эффективно обрабатывает соединения. Однако помните, что если в документе Контрагент не заполнен, такая строка также пропадет из результата.

Способ 3. Использование временных таблиц с индексацией

Если задача требует сложной логики (например, нужно сохранить пустые ссылки, но убрать «Объект не найден»), можно использовать временные таблицы (ВТ). Этот метод был предложен в обсуждении как способ явно разделить выборку доступных контрагентов и выборку документов.

Разберем по шагам реализацию с учетом оптимизации для миллионов записей:

  1. Выбираем все разрешенные ссылки из справочника во временную таблицу.
  2. Обязательно индексируем временную таблицу по полю Ссылка.
  3. Соединяем таблицу документов с этой ВТ.

Пример реализации:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Контрагенты.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_РазрешенныеКонтрагенты
ИЗ
    Справочник.Контрагенты КАК Контрагенты
ИНДЕКСИРОВАТЬ ПО
    Ссылка
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Док.Организация,
    Док.Подразделение,
    Док.Контрагент
ИЗ
    Документ.ПоступлениеИнформации КАК Док
ГДЕ
    (Док.Контрагент В (ВЫБРАТЬ ВТ.Ссылка ИЗ ВТ_РазрешенныеКонтрагенты КАК ВТ)
    ИЛИ Док.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка))

Внимание: на больших объемах данных (миллионы записей) создание временной таблицы может занимать значительное время (в обсуждении упоминалось около 15 секунд). Если важна мгновенная реакция системы, лучше использовать Способ 1 или Способ 2.

Обработка пустых ссылок

Часто возникает вопрос: как не потерять пустые значения при фильтрации «битых» ссылок? Посмотрим на пример кода, который изящно решает эту задачу через ЛЕВОЕ СОЕДИНЕНИЕ и проверку на NULL:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Док.Контрагент,
    Док.Организация
ИЗ
    Документ.ПоступлениеИнформации КАК Док
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты
        ПО Док.Контрагент = Контрагенты.Ссылка
ГДЕ
    ВЫБОР
        КОГДА Док.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
            ТОГДА ИСТИНА
        ИНАЧЕ НЕ Контрагенты.Ссылка ЕСТЬ NULL
    КОНЕЦ

В данном случае, если контрагент в документе не пустой, но его нет в «разрешенной» таблице справочника (результат RLS), то Контрагенты.Ссылка будет NULL, и условие ИНАЧЕ отфильтрует такую строку. Пустые же ссылки пройдут проверку в первом условии КОГДА.

Рекомендации по производительности

Проанализировав ситуацию с миллионами записей, можно сделать следующие выводы:

Таким образом, мы рассмотрели основные способы борьбы с «невидимыми» объектами в запросах. Выбор конкретного метода зависит от требований к обработке пустых ссылок и объема данных в вашей базе.

← На главную