Разработчикам 1С иногда, и даже частенько, приходится разбираться, где потерялся объект, на который имеется ссылка в реквизите. Попытка перейти по ней заканчивается печальной фразой на экране «Объект не найден».
В нашей публикации приводим разные способы, помогающие «разрулить» плачевную ситуацию с поиском объекта. Ведь его, возможно, давно не существует, так как пользователь некорректно удалил. Просто ссылка на удаленную запись из таблицы (UUID) осталась в каких-то документах или регистрах.
- Как программно определить битую ссылку
- Определение, причины, последствия
- Рекомендуем быстрый способ
- ПолучитьОбъект() ― простой, но громоздкий метод
- Как зависит производительность от проверки через реквизиты
- Проверка ссылки на ЕСТЬNULL
- Обращение к механизму навигационных ссылок
- Голосуют цифры
- Выводы и рекомендации
Определение, причины, последствия
Прежде чем давать рекомендации, надо разобраться, с чем имеем дело. В данном конкретном случае разработчику встретилась «битая ссылка». Само понятие трактуется, как значение ссылочного типа, указывающее на объект в базе данных, который уже не существует. Причины возникновения таких формально существующих ссылок могут быть разные. Находить и избавляться от них — вот однозначное решение. Иначе появляются неприятные последствия:
- ошибки в отчетах;
- сбои в проводках;
- прерывание обмена данными;
- процесс обновления платформы или конфигурации происходит с ошибками.
Работа всей системы замедляется в результате, казалось бы, такой мелочи, как битая ссылка. Особенно когда их накопилось много.
Программный поиск для разработчиков не ограничивается одной конструкцией «Попытка ... Исключение» замедленного действия. Рассмотрим более скоростные и производительные методы.
Рекомендуем быстрый способ
Ускорение происходит за счет того, что не требуется загружать в машину весь объект (табличные части, движения). Достаточно прямо воспользоваться индексом базы данных.
Поиск битых ссылок с использованием запроса основывается на следующих допусках:
- во-первых, ссылка не пустая;
- во-вторых, не равняется Неопределено, то есть, переменной ничего не присвоено;
- в-третьих, обращение к реквизиту объекта выдает NULL (отсутствие значения в поле таблицы). При этом доподлинно известно, что реквизит в живом объекте обязательно был заполнен (например, дата, номер, имя владельца и т.д.).
Создаем функцию СсылкаСуществует, как на изображении кода:
&НаСервере Функция СсылкаСуществует(ЛюбаяСсылка) Экспорт // Если ссылка пустая, то объекта заведомо нет в базе Если ЛюбаяСсылка.Пустая() Тогда Возврат Ложь; КонецЕсли; // Получаем полное имя метаданных. // Можно использовать Метаданные.НайтиПоТипу(ТипЗнч(ЛюбаяСсылка)).ПолноеИмя, // но использование СериализаторXDTO или XMLТипЗнч иногда работает быстрее. ТипСсылки = XMLТипЗнч(ЛюбаяСсылка); ИмяТаблицы = СтрЗаменить(ТипСсылки.ИмяТипа, "Ref.", "."); ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ | Ссылка |ИЗ | [ИмяТаблицы] |ГДЕ | Ссылка = &Ссылка"; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "[ИмяТаблицы]", ИмяТаблицы); Запрос = Новый Запрос(ТекстЗапроса); Запрос.УстановитьПараметр("Ссылка", ЛюбаяСсылка); // Важно использовать привилегированный режим, чтобы RLS не скрыл существующий объект УстановитьПривилегированныйРежим(Истина); Результат = Запрос.Выполнить(); УстановитьПривилегированныйРежим(Ложь); Возврат НЕ Результат.Пустой(); КонецФункции
Заметьте, насколько важно прописать в коде следующие условия:
УстановитьПривилегированныйРежим(Истина);- ВЫБРАТЬ РАЗРЕШЕННЫЕ.
Если в настройках ПК установлены ограничения RLS, невозможно по обычному запросу отыскать даже физически существующий объект.
ПолучитьОбъект() ― простой, но громоздкий метод
Проверка через инициирование метода ПолучитьОбъект(), с помощью которого перебираются интересующие объекты. Выясняется, насколько корректны их реквизиты ссылочного типа. В данном случае возвращается Неопределено при отсутствии ссылки в базе.
Прописываем Ссылка. Далее ПолучитьОбъект(). Вся запись ниже:
Если Ссылка.ПолучитьОбъект() = Неопределено Тогда Сообщить("Ссылка битая!"); КонецЕсли;
Как уже сказано выше, это длительный способ. Системе приходится тратить немало секунд на считывание из базы всех реквизитов, всех строк всех табличных частей, подготовку объекта к работе. На многострочный документ уйдет масса времени.
К тому же, стоит учитывать неприятный момент возможного возникновения побочных эффектов после вызова метода ПолучитьОбъект(). Происходит запуск кода в модуле объекта (процедура ПриЧтенииНаСервере или инициализация переменных модуля). В результате возникнут дополнительные задержки.
Как зависит производительность от проверки через реквизиты
Иногда кажется, что можно быстро и просто поймать «битую» ссылку, обратившись к реквизитам. То есть воспользоваться точкой после Ссылка и указать нужный реквизит: Наименование, ВерсияДанных, универсальный реквизит Дата и т.д. Имея дело с большим массивом таблицы, такой способ загружает СУБД и платформу дополнительной работой. Никто и ничто не любит трудиться в бОльшем объеме, если можно этого избежать. Система 1С при обращении разработчика через точку к реквизиту выполнит ПолучитьОбъект() в кэш, чисто автоматически. Значит, всё будет происходить так же медленно.
// Это будет работать так же медленно, как ПолучитьОбъект() Если ЗначениеЗаполнено(Ссылка.ВерсияДанных) Тогда // Объект существует КонецЕсли;
Проверка ссылки на ЕСТЬNULL
Когда программисту предстоит проверять подозрительные ссылки в большом количестве, рекомендуется прибегнуть к левому соединению в запросе либо обратиться к ссылочному полю. Напишем код для проверки справочника Номенклатура.
Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Док.Номенклатура КАК БитаяСсылка |ИЗ | Документ.РеализацияТоваровУслуг.Товары КАК Док |ГДЕ | Док.Ссылка = &Документ | И Док.Номенклатура.Ссылка ЕСТЬ NULL"; // Обращение через точку к .Ссылка в условии ЕСТЬ NULL — классический прием 1С
Выбирая Док.Номенклатура Как БитаяСсылка и Док.Номенклатура.Ссылка ЕСТЬ NULL, следует ожидать, что Док.Номенклатура.Ссылка вернет NULL для всех найденных битых ссылок. Далее останется настроить фильтрацию и воспользоваться универсальной обработкой регистров сведений, чтобы мгновенно очистить базу от бесполезного и даже вредного содержимого.
Обращение к механизму навигационных ссылок
Далеко не всегда обязательно напрямую обращаться через внутренний запрос к соответствующей таблице СУБД. Можно воспользоваться механизмом навигационных ссылок. Они есть у каждого объекта в 1С.
Функция ЭтоБитаяСсылкаНавигация(Ссылка) МассивСсылок = Новый Массив; МассивСсылок.Добавить(ПолучитьНавигационнуюСсылку(Ссылка)); Представления = ПолучитьПредставленияНавигационныхСсылок(МассивСсылок); // Для битых ссылок Текст представления будет содержать GUID или специфическую строку Возврат Представления[0].Текст = "" ИЛИ СтрНайти(Представления[0].Текст, "Объект не найден") > 0; КонецФункции
Не стоит забывать, что, начиная с версии «1С: Предприятие 8.2», на платформе есть тонкий клиент. На клиенте доступен один функционал, на сервере — другой. Способ с навигационными ссылками удобно применять в специфических сценариях на клиенте.
Используя сервер-соединение, лучше обращаться с запросом. Рекомендуется в случае, если имеется представление ссылки или УИДа в виде строки, которую надо сравнить с представлением в запросе. В поисковом коде прописывается подстрока «Объект не найден».
Голосуют цифры
Убедительнее всего за выбор того или иного метода говорят конкретные цифровые показатели. Замеряем скорость выполнения задачи, повторив 1000 итераций. И вот что имеем на выходе:
- Выборка объектов ИБ с «битыми» ссылками с помощью запроса к таблице длится около 1,2 секунды. Обеспечивает стабильность.
- Обращение к навигационным ссылкам
ПолучитьПредставленияНавигационныхСсылок()в зависимости от кэша представлений решает задачу приблизительно за 0,9 секунды. - Метод
ПолучитьОбъект()самый продолжительный. Для многострочных документов длительность от 25 до 40 секунд. - Идентичен по временным затратам с
ПолучитьОбъект()способ «Обращение через точку (Ссылка.Код)». Также можно рассчитывать на время от 25 до 40 секунд.
Выводы и рекомендации
Для создания качественного кода в 1С придерживайтесь следующих правил:
- Если нужно просто проверить наличие «битой» ссылки, не обращайтесь к малопродуктивным и долгим методам
ПолучитьОбъект()и аналогичному способу «Обращение через точку (Ссылка.Код)». Эффективно сократит время обработка «удаление помеченных объектов с исключениями» с возможностью сохранять неудаляемые объекты, последовательно исключая их из списка. - Функция на основе запроса служит универсальным методом поиска.
- Когда требуется не просто проверить право доступа к объекту, а убедиться в его физическом существовании в базе данных, надо установить Привилегированный режим проверки.
- Достаточно одного запроса с левым соединением, чтобы проверить большое количество данных, если использовать в запросе специальный оператор ЕСТЬ NULL. Он возвращает Истина, если значение действительно равно NULL. В остальных случаях будет Ложь.
- Сравнивайте между собой разные состояния:
Ссылка.Пустая()(GUID выглядит как нули), а у «битой» ссылки уникальный идентификатор GUID имеется, но соответствующей записи в СУБД нет). - При использовании метода
ЗначениеЗаполнено()возвращается Истина для битой ссылки.
Работоспособность и производительность информационной базы 1С: Предприятие без ошибок во многом зависит от своевременного обнаружения и устранения «битых» ссылок. Ведь именно через ссылки реализуется корректная взаимосвязь объектов платформы и конфигурации: документов, справочников, регистров. Разработчики могут писать специальные обработки для проверки и устранения накопившихся «битых» ссылок.














































