В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача предоставить пользователю возможность очистить "свои" данные в независимом регистре сведений. Если в системе настроено разграничение прав доступа на уровне записей (RLS), стандартные методы перебора записей могут приводить к фатальным ошибкам. В этой статье мы подробно разберем, почему обычная выборка не работает и как правильно реализовать удаление доступных записей, используя современные возможности платформы.
Рассмотрим ситуацию: программист пишет код, который должен пройти по всем записям регистра и удалить их. Типичный код выглядит так:
Выборка = РегистрыСведений.НазваниеРегистра.Выбрать();
Пока Выборка.Следующий() Цикл
Выборка.ПолучитьМенеджерЗаписи().Удалить();
КонецЦикла;
Если в регистре есть записи, которые текущему пользователю недоступны согласно правилам RLS, метод Следующий() вызовет исключение: "У пользователя недостаточно прав на исполнение операции над базой данных". Это происходит потому, что объектный метод Выбрать() пытается прочитать данные, на которые у пользователя нет прав. Выясним, как обойти это ограничение.
Для того чтобы система игнорировала записи, к которым у пользователя нет доступа, необходимо использовать механизм запросов. В языке запросов 1С существует специальная инструкция РАЗРЕШЕННЫЕ, которая фильтрует результат на уровне СУБД, оставляя только те строки, которые проходят проверку RLS.
Проанализируем алгоритм решения по шагам:
РАЗРЕШЕННЫЕ сразу после ВЫБРАТЬ.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| *
|ИЗ
| РегистрСведений.НазваниеРегистра КАК НазваниеРегистра";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Создаем менеджер записи для конкретной строки
МенеджерЗаписи = РегистрыСведений.НазваниеРегистра.СоздатьМенеджерЗаписи();
// Заполняем измерения из выборки запроса
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, Выборка);
// Удаляем запись
МенеджерЗаписи.Удалить();
КонецЦикла;
Этот метод надежен, так как запрос не "спотыкается" о чужие записи, а просто не видит их.
Начиная с версии платформы 8.3.23, появился более производительный способ удаления записей. Вместо того чтобы удалять каждую запись в цикле (что порождает множество транзакций и обращений к базе данных), мы можем использовать РежимЗамещения.Удаление.
Рассмотрим, как реализовать это правильно, избежав типичных ошибок типизации:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ * ИЗ РегистрСведений.НазваниеРегистра";
// Важно: Выгружаем результат в Таблицу Значений
УдаляемыеЗаписи = Запрос.Выполнить().Выгрузить();
Если УдаляемыеЗаписи.Количество() > 0 Тогда
НаборЗаписей = РегистрыСведений.НазваниеРегистра.СоздатьНаборЗаписей();
// Загружаем таблицу в набор. Платформа сопоставит колонки по именам.
НаборЗаписей.Загрузить(УдаляемыеЗаписи);
// Используем специальный режим записи для удаления
НаборЗаписей.Записать(Истина, РежимЗамещения.Удаление);
КонецЕсли;
Важный нюанс: метод Загрузить() ожидает объект типа ТаблицаЗначений. Если вы попытаетесь передать туда ВыборкаИзРезультатаЗапроса, система выдаст ошибку несоответствия типов. Поэтому использование метода Выгрузить() обязательно.
Разберем несколько критически важных моментов, которые обеспечат стабильность вашей системы при массовом удалении данных:
Выгрузить() может переполнить оперативную память сервера. В таких случаях рекомендуем использовать порционное удаление (например, по 5000 записей за раз).РАЗРЕШЕННЫЕ в запросе проверяет право на Чтение. Однако для удаления записи пользователю необходимо иметь право на Изменение. Если RLS настроен так, что чтение разрешено, а изменение — нет, то метод Записать() или Удалить() все равно вызовет ошибку прав доступа.РАЗРЕШЕННЫЕ убедитесь, что поля, по которым настроены ограничения (например, Автор, Организация), проиндексированы. Это предотвратит полное сканирование таблицы БД (Full Scan) и снизит количество блокировок.Проанализировав ситуацию, мы выяснили, что наиболее эффективным и правильным подходом является сочетание запроса с инструкцией РАЗРЕШЕННЫЕ и последующая обработка данных через НаборЗаписей. Это минимизирует нагрузку на СУБД и гарантирует корректную работу в условиях жесткого разграничения прав доступа.