Как удалить "свои" записи из регистра сведений при включенном RLS

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача предоставить пользователю возможность очистить "свои" данные в независимом регистре сведений. Если в системе настроено разграничение прав доступа на уровне записей (RLS), стандартные методы перебора записей могут приводить к фатальным ошибкам. В этой статье мы подробно разберем, почему обычная выборка не работает и как правильно реализовать удаление доступных записей, используя современные возможности платформы.

Анализ проблемы: Почему метод Выбрать() вызывает ошибку

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


Выборка = РегистрыСведений.НазваниеРегистра.Выбрать();
Пока Выборка.Следующий() Цикл
    Выборка.ПолучитьМенеджерЗаписи().Удалить();
КонецЦикла;

Если в регистре есть записи, которые текущему пользователю недоступны согласно правилам RLS, метод Следующий() вызовет исключение: "У пользователя недостаточно прав на исполнение операции над базой данных". Это происходит потому, что объектный метод Выбрать() пытается прочитать данные, на которые у пользователя нет прав. Выясним, как обойти это ограничение.

Решение 1: Использование запроса с инструкцией РАЗРЕШЕННЫЕ

Для того чтобы система игнорировала записи, к которым у пользователя нет доступа, необходимо использовать механизм запросов. В языке запросов 1С существует специальная инструкция РАЗРЕШЕННЫЕ, которая фильтрует результат на уровне СУБД, оставляя только те строки, которые проходят проверку RLS.

Проанализируем алгоритм решения по шагам:

  1. Создадим запрос к регистру сведений.
  2. Добавим ключевое слово РАЗРЕШЕННЫЕ сразу после ВЫБРАТЬ.
  3. В цикле обхода результата запроса будем создавать менеджер записи, заполнять его измерения и выполнять удаление.

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |   *
    |ИЗ
    |   РегистрСведений.НазваниеРегистра КАК НазваниеРегистра";

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    // Создаем менеджер записи для конкретной строки
    МенеджерЗаписи = РегистрыСведений.НазваниеРегистра.СоздатьМенеджерЗаписи();
    
    // Заполняем измерения из выборки запроса
    ЗаполнитьЗначенияСвойств(МенеджерЗаписи, Выборка);
    
    // Удаляем запись
    МенеджерЗаписи.Удалить();
КонецЦикла;

Этот метод надежен, так как запрос не "спотыкается" о чужие записи, а просто не видит их.

Решение 2: Массовое удаление через НаборЗаписей (современный способ)

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

Рассмотрим, как реализовать это правильно, избежав типичных ошибок типизации:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ * ИЗ РегистрСведений.НазваниеРегистра";

// Важно: Выгружаем результат в Таблицу Значений
УдаляемыеЗаписи = Запрос.Выполнить().Выгрузить();

Если УдаляемыеЗаписи.Количество() > 0 Тогда
    НаборЗаписей = РегистрыСведений.НазваниеРегистра.СоздатьНаборЗаписей();
    
    // Загружаем таблицу в набор. Платформа сопоставит колонки по именам.
    НаборЗаписей.Загрузить(УдаляемыеЗаписи);
    
    // Используем специальный режим записи для удаления
    НаборЗаписей.Записать(Истина, РежимЗамещения.Удаление);
КонецЕсли;

Важный нюанс: метод Загрузить() ожидает объект типа ТаблицаЗначений. Если вы попытаетесь передать туда ВыборкаИзРезультатаЗапроса, система выдаст ошибку несоответствия типов. Поэтому использование метода Выгрузить() обязательно.

Оптимизация и безопасность при работе с RLS

Разберем несколько критически важных моментов, которые обеспечат стабильность вашей системы при массовом удалении данных:

  1. Контроль памяти: Если у пользователя могут быть сотни тысяч "своих" записей, метод Выгрузить() может переполнить оперативную память сервера. В таких случаях рекомендуем использовать порционное удаление (например, по 5000 записей за раз).
  2. Различие прав: Помните, что РАЗРЕШЕННЫЕ в запросе проверяет право на Чтение. Однако для удаления записи пользователю необходимо иметь право на Изменение. Если RLS настроен так, что чтение разрешено, а изменение — нет, то метод Записать() или Удалить() все равно вызовет ошибку прав доступа.
  3. Индексация: Для быстрой работы запроса с РАЗРЕШЕННЫЕ убедитесь, что поля, по которым настроены ограничения (например, Автор, Организация), проиндексированы. Это предотвратит полное сканирование таблицы БД (Full Scan) и снизит количество блокировок.
  4. Привилегированный режим: Если бизнес-логика требует удаления записей, на которые у пользователя нет прав "Изменение", но он инициирует этот процесс, код удаления следует вынести в общий модуль с включенным признаком Привилегированный. При этом предварительный отбор "своих" записей всё равно нужно сделать в обычном режиме, чтобы не удалить лишнего.

Проанализировав ситуацию, мы выяснили, что наиболее эффективным и правильным подходом является сочетание запроса с инструкцией РАЗРЕШЕННЫЕ и последующая обработка данных через НаборЗаписей. Это минимизирует нагрузку на СУБД и гарантирует корректную работу в условиях жесткого разграничения прав доступа.

← На главную