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