Как определить программно ссылка битая или нет ?
По теме из базы знаний
Ответы
Подписаться на ответы
Инфостарт бот
Сортировка:
Древо развёрнутое
Свернуть все
(1) В БСП есть функция
// Проверяет физическое наличие записи в информационной базе данных о переданном значении ссылки
//
// Параметры:
// ЛюбаяСсылка - значение любой ссылки информационной базы данных
//
// Возвращаемое значение:
// Истина - ссылка физически существует;
// Ложь - ссылка физически не существует
//
Функция СсылкаСуществует(ЛюбаяСсылка) Экспорт
ТекстЗапроса = "
|ВЫБРАТЬ
| Ссылка
|ИЗ
| [ИмяТаблицы]
|ГДЕ
| Ссылка = &Ссылка
|";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "[ИмяТаблицы]", ИмяТаблицыПоСсылке(ЛюбаяСсылка));
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Ссылка", ЛюбаяСсылка);
УстановитьПривилегированныйРежим(Истина);
Возврат НЕ Запрос.Выполнить().Пустой();
КонецФункции
Показать
Rastopchinss; Somebody1; Elucidator7b; Mingrel; user1619761; Pigzilla; Monex; prog2019; Рамзес; hityay; FilatovRA; exclusive; syurev; user1716460; ghostaz; sumpavig; Andy_NTG; akocur; alsegor; pioneeer; jobkostya1c_ERP; simuljakr; Student1C; Gendelf; Merkalov; vv2; LordKim; Lacoste4life; RomanKod; Sarkikker; Andrei_Ivanov; houpl; user1232941; Fales; v3n7; unknown181538; GonziK_KIV; malikov_pro; Jivchic; ram3; TeMochkiN; maxunov95; improg; kimskiysanya; mickey.1cx; Batman; zfr475; user659168_xec8787; anchovy; 7OH; treedo; McLer; Alien_job; by_1Cnik; rusmil; adhocprog; serezhenko; Gladkov_Anton; azazana; gaspard; alex-l19041; Патриот; Kesak; HEKPOH; Dr.ZIG; pintov;
+66
–
Ответить
(10) nodalt,
// Возвращает полное имя объекта метаданных по переданному значению ссылки
// Например,
// "Справочник.Номенклатура";
// "Документ.ПриходнаяНакладная"
//
// Параметры:
// Ссылка - ЛюбаяСсылка - значение ссылки, для которого необходимо получить имя таблицы ИБ
//
// Возвращаемое значение:
// Строка - полное имя объекта метаданных для указанного значения ссылки
//
Функция ИмяТаблицыПоСсылке(Ссылка) Экспорт
Возврат Метаданные.НайтиПоТипу(ТипЗнч(Ссылка)).ПолноеИмя();
КонецФункции
Показать
Думаю как вариант банально анализировать представление формируемое платформой 1С
Ссылка = Реквизит1.Родитель;
Если Найти(Строка(Ссылка), "<Объект не найден> (" ) <> 0 тогда
Сообщить("Ссылка битая");
Иначе
Сообщить("Ссылка НЕ битая");
КонецЕсли;
Показать
(4) ksb, just for lulz:
НовЭл = Справочники.Справочник.СоздатьЭлемент();
НовЭл.Наименование = "Сейчас мы <Объект не найден> ( поломаем систему";
НовЭл.Записать();
Ссылка = НовЭл.Ссылка;
Если Найти(Строка(Ссылка), "<Объект не найден> (" ) <> 0 тогда
Сообщить("Ссылка битая");
Иначе
Сообщить("Эта ветка нам не понадобится, можно её удалить");
КонецЕсли;
Показать
(13) Блин, хоть ветка старая, но... Чуваки и чувихи, которые ищут объекты не найденные скорее всего это делают относительно не часто, и вряд ли им попадется маньяк, который так будет делать. Понимаю что учитывать надо, но ровно с той же вероятностью, даже кстати меньшей, чем то что конфа будет в режиме совместимости с 8.3.5 и ниже. "Найти" там, вся фигня...
(12) Простите, что "оживляю" мертвую ветку.
Только что наступил на еще одну граблю в пользу запроса (из функции СсылкаСуществует) против Ссылка.ПолучитьОбъект() = Неопределено.
Получение объекта, кроме зачитывания из БД кучи табличных частей и движений документа, еще и выполняет код инициализации модуля объекта... А некоторые доброжелатели (из разработчиков типовых конфигураций) там ТАКИХ сюрпризов наоставлять могут, что вся производительность в ноль уйдет.
Только что наступил на еще одну граблю в пользу запроса (из функции СсылкаСуществует) против Ссылка.ПолучитьОбъект() = Неопределено.
Получение объекта, кроме зачитывания из БД кучи табличных частей и движений документа, еще и выполняет код инициализации модуля объекта... А некоторые доброжелатели (из разработчиков типовых конфигураций) там ТАКИХ сюрпризов наоставлять могут, что вся производительность в ноль уйдет.
Извиняюсь за некропост, но с некоторой версии платформы появился встроенный реквизит ссылочного объекта "ВерсияДанных", который заполняется системой в момент записи объекта. Значит если объекта нет, то это значение будет не заполнено.
ЭтоБитаяСсылка = ПустаяСтрока(Ссылка.ВерсияДанных);
(20) Замеры показывают, что Ссылка.ВерсияДанных, Ссылка.Номер, Ссылка.ЛюбойРеквизит - выполняются по времени соизмеримо с Ссылка.ПолучитьОбъект().
И это правильно, т.к. если вспоминать мат. часть, то выяснится, что для получения реквизита через точку, платформа зачитывает в память весь объект, со всеми табличными частями и движениями (если это документ), и получает от него реквизит. И кстати, сам объект какое-то время висит в кэш-памяти - на случай, если надо будет от него через точку еще какие-нибудь реквизиты получать.
Посему вывод: функция СсылкаСуществует - самый быстрый способ проверки (особенно если еще и саму функцию в кэшируемый модуль поместить).
И это правильно, т.к. если вспоминать мат. часть, то выяснится, что для получения реквизита через точку, платформа зачитывает в память весь объект, со всеми табличными частями и движениями (если это документ), и получает от него реквизит. И кстати, сам объект какое-то время висит в кэш-памяти - на случай, если надо будет от него через точку еще какие-нибудь реквизиты получать.
Посему вывод: функция СсылкаСуществует - самый быстрый способ проверки (особенно если еще и саму функцию в кэшируемый модуль поместить).
в запросе однозначно лучше всего и проверено, например проверить документы с битой ссылкой на контрагент: Документ.Контрагент.Ссылка ЕСТЬ NULL обязательно надо добавлять .Ссылка чтобы там NULL получился у битой ссылке.
Как выяснилось эксперементальным путем для проверки на "Объект не найден" быстрее работает конструкция
нежели
Применял в конвертации данных на стадии выгрузки набора движений документа на очень больших объемах данных где в единичных случаях попадались битые ссылки и процесс прерывался.
Через COM такой подход тоже будет работать только типа
Отказ = СтрНайти(Строка(БитаяСсылка),"<Объект не найден>") > 0;
нежели
Отказ = БитаяСсылка.ПолучитьОбъект() = Неопределено;
Применял в конвертации данных на стадии выгрузки набора движений документа на очень больших объемах данных где в единичных случаях попадались битые ссылки и процесс прерывался.
Через COM такой подход тоже будет работать только типа
СтрНайти(Соединение.Строка(БитаяСсылка),"<Объект не найден>")
(37) Это не самое оптимальное решение.
Очевидно же, что единственный нативный способ проверить существование объекта – это запрос: Ничего быстрее вы не придумаете.
Очевидно же, что единственный нативный способ проверить существование объекта – это запрос:
Запрос = Новый Запрос("ВЫБРАТЬ NULL ИЗ Справочник.МойСправочник ГДЕ Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", БитаяСсылка);
СсылкаБитая = Запрос.Выполнить().Пустой();
Если ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Документ, "Ссылка") = Неопределено Тогда // сгенерирована ссылка без описания объекта
ТекстСообщения = СтрШаблон(НСтр("ru = 'Не обработана строка фабрики XDTO ReturnFlow:
|Не обнаружена заявка на закупку с идентификатором %1'"), UUID);
ВызватьИсключение ТекстСообщения;
КонецЕсли;
// Проверка существует ли объект по ссылке
Функция СсылкаСуществует(СсылкаНаОбъект)
Запрос = Новый Запрос("Выбрать Таб.Ссылка ИЗ "+СтрЗаменить(СериализаторXDTO.XMLТипЗнч(СсылкаНаОбъект).ИмяТипа,"Ref.",".") +" КАК Таб ГДЕ Таб.Ссылка = &СсылкаНаОбъект");
Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект);
Результат = Запрос.Выполнить();
Возврат НЕ Результат.Пустой();
КонецФункции
Показать
(31)
Совершенно согласен с подходом. Поясню.
Здесь много говорили о производительности. И запросом ссылку проверять быстрее и правильнее, не загружая объект в память.
Однако, ни кто не обратил внимание на составную функции СсылкаСуществует()
Там используется другая функция ИмяТаблицыПоСсылке(), которая берет Метаданные() объекта.
Замерил, - это примерно 10 раз медленнее чем XMLТипЗнч() (на цикле в 10000).
Проверить может каждый. Замер времени делал просто - обернул код вызова ТекущаяУниверсальнаяДатаВМиллисекундах() и узнал разницу.
Да, XMLТипЗнч() изменяет описание объекта. Вместо "Справочник.Номенклатура" она возвращает "CatalogRef.Номенклатура", поэтому приходится использовать дополнительно СтрЗаменить(). Для запроса не играет роли как мы обзываем тип объекта, - "Catalog." или "Справочник.".
Поэтому переписал функцию. Мне же потом и пригодится. Помещу здесь новый вариант:
Запрос = Новый Запрос("Выбрать Таб.Ссылка ИЗ "+СтрЗаменить(СериализаторXDTO.XMLТипЗнч(СсылкаНаОбъект).ИмяТипа,"Ref.",".") +" КАК Таб ГДЕ Таб.Ссылка = &СсылкаНаОбъект");
Совершенно согласен с подходом. Поясню.
Здесь много говорили о производительности. И запросом ссылку проверять быстрее и правильнее, не загружая объект в память.
Однако, ни кто не обратил внимание на составную функции СсылкаСуществует()
Там используется другая функция ИмяТаблицыПоСсылке(), которая берет Метаданные() объекта.
Замерил, - это примерно 10 раз медленнее чем XMLТипЗнч() (на цикле в 10000).
Проверить может каждый. Замер времени делал просто - обернул код вызова ТекущаяУниверсальнаяДатаВМиллисекундах() и узнал разницу.
Да, XMLТипЗнч() изменяет описание объекта. Вместо "Справочник.Номенклатура" она возвращает "CatalogRef.Номенклатура", поэтому приходится использовать дополнительно СтрЗаменить(). Для запроса не играет роли как мы обзываем тип объекта, - "Catalog." или "Справочник.".
Поэтому переписал функцию. Мне же потом и пригодится. Помещу здесь новый вариант:
&НаСервере
Функция СсылкаСуществует(ЛюбаяСсылка) Экспорт
//ИмяТаблицы = Метаданные.НайтиПоТипу(ТипЗнч(ЛюбаяСсылка)).ПолноеИмя(); // взять Метаданные() в 10 раз медленнее чем XMLТипЗнч(..)
ИмяТаблицы = СтрЗаменить(СериализаторXDTO.XMLТипЗнч(ЛюбаяСсылка).ИмяТипа, "Ref.", ".");
ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ Ссылка ИЗ [ИмяТаблицы] ГДЕ Ссылка = &Ссылка";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "[ИмяТаблицы]", ИмяТаблицы);
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Ссылка", ЛюбаяСсылка);
УстановитьПривилегированныйРежим(Истина);
Результ = НЕ Запрос.Выполнить().Пустой();
УстановитьПривилегированныйРежим(Ложь);
Возврат Результ;
КонецФункции
Показать
И снова: -Здравствуйте!
Предлагаю рассмотреть ещё один вариант определения существования объекта по ссылке - через наличие представления навигационной ссылки.
Не могу сказать, что он 100% корректный, так как если у некоторых объектов представлением будет "", то он не применим.
В прикрепленной обработке есть тест на 2000 итераций, а также функция пакетной проверки ПолучитьМассивСуществующихОбъектовСсылок(массивСсылок)
Результаты замеров на 2000 итераций:
БСПшный СсылкаСуществует(): 12.683;
ПолучитьПризнакСуществуетОбъектСсылки(Ссылка): 7.251;
ПолучитьМассивСуществующихОбъектовСсылок(массивСсылок): 1.830;
Если посмотреть на объект ПредставлениеНавигационнойСсылки, то с 8.3.13 у него есть метод Представление():
Для корректных ссылок возвращает - значение свойства Текст.
Для некорректных ссылок (ссылка неправильно сформирована, объект отсутствует в базе, объект метаданных отсутствует, или у пользователя нет права на объект) - значение свойства НавигационнаяСсылка.
Получается можно также сравнивать эти свойства с результатом этого метода, для определения существования объекта
Предлагаю рассмотреть ещё один вариант определения существования объекта по ссылке - через наличие представления навигационной ссылки.
Не могу сказать, что он 100% корректный, так как если у некоторых объектов представлением будет "", то он не применим.
Функция ПолучитьПризнакСуществуетОбъектСсылки(Ссылка)
массивНС = новый массив(1);
УстановитьПривилегированныйРежим(Истина);
массивНС[0] = ПолучитьНавигационнуюСсылку(Ссылка);
Возврат ПолучитьПредставленияНавигационныхСсылок(массивНС)[0].Текст <> "";
КонецФункции
В прикрепленной обработке есть тест на 2000 итераций, а также функция пакетной проверки ПолучитьМассивСуществующихОбъектовСсылок(массивСсылок)
Результаты замеров на 2000 итераций:
БСПшный СсылкаСуществует(): 12.683;
ПолучитьПризнакСуществуетОбъектСсылки(Ссылка): 7.251;
ПолучитьМассивСуществующихОбъектовСсылок(массивСсылок): 1.830;
Если посмотреть на объект ПредставлениеНавигационнойСсылки, то с 8.3.13 у него есть метод Представление():
Для корректных ссылок возвращает - значение свойства Текст.
Для некорректных ссылок (ссылка неправильно сформирована, объект отсутствует в базе, объект метаданных отсутствует, или у пользователя нет права на объект) - значение свойства НавигационнаяСсылка.
Получается можно также сравнивать эти свойства с результатом этого метода, для определения существования объекта
Прикрепленные файлы:
ВнешняяОбработка_ПолучениеНавигационныхСсылокТест.epf
(45)
Результаты замера по массиву ссылок привёл только для демонстрации возможности и отражения разницы.
Кстати, проверил выполнение на серверной стороне, 1000 итераций :
Проверка через запрос к таблице ~ 1200мс;
Проверка через представления навигационной ссылки ~ 900мс;
Кстати стандартное представление ссылок с пустым наименованием "<>", таким образом условие проверки Текст <> "" будет работать*.
-----
*До тех пор, пока кто-то не "сломает" процедуру ОбработкаПолученияПредставления() в модуле менеджера метаданных. XD
Результаты замера по массиву ссылок привёл только для демонстрации возможности и отражения разницы.
Кстати, проверил выполнение на серверной стороне, 1000 итераций :
Проверка через запрос к таблице ~ 1200мс;
Проверка через представления навигационной ссылки ~ 900мс;
Кстати стандартное представление ссылок с пустым наименованием "<>", таким образом условие проверки Текст <> "" будет работать*.
-----
*До тех пор, пока кто-то не "сломает" процедуру ОбработкаПолученияПредставления() в модуле менеджера метаданных. XD
(46) Вы тестируете в режиме обычного приложения, там код выполняется на клиенте, пока не доходит до строк, требующих обращение к серверу, поэтому эксперимент не чистый. Проведите свои замеры в общем модуле с галками Сервер и ВызовСервера на клиент-серверной базе – результаты будут другие: чистый запрос будет стабильно быстрее, хотя и не значительно.
Либо протестируйте приложенную обработку на управляемых формах (тонкий клиент), там можно четко контролировать контекст выполнения.
Либо протестируйте приложенную обработку на управляемых формах (тонкий клиент), там можно четко контролировать контекст выполнения.
Прикрепленные файлы:
ПроверкаБыстродействияОпределенияБитойСсылки.epf
(47)
Согласен, нет ничего надёжнее и быстрее, чем обращение непосредственно к данным СУБД.
Меня ввел в заблуждение не контекст выполнения алгоритма, а конкретная ИБ :).
Проверил на ней ваш обработчик в разных режимах предприятия - получил те же результаты (представление ссылки получает быстрее).
Однако на другом сервере 1С/СУБД, где не включен debug и который пошустрее, запросом значительно быстрее (x2).
Из этого делаю вывод, что чем меньше операций на "голом" 1С, тем лучше :)
По сути ПолучитьПредставленияНавигационныхСсылок() выполняет тот же запрос к таблице с искомыми ссылками, но при этом дополнительно вызывает обработчик функции ПРЕДСТАВЛЕНИЕ().
Согласен, нет ничего надёжнее и быстрее, чем обращение непосредственно к данным СУБД.
Меня ввел в заблуждение не контекст выполнения алгоритма, а конкретная ИБ :).
Проверил на ней ваш обработчик в разных режимах предприятия - получил те же результаты (представление ссылки получает быстрее).
Однако на другом сервере 1С/СУБД, где не включен debug и который пошустрее, запросом значительно быстрее (x2).
Из этого делаю вывод, что чем меньше операций на "голом" 1С, тем лучше :)
По сути ПолучитьПредставленияНавигационныхСсылок() выполняет тот же запрос к таблице с искомыми ссылками, но при этом дополнительно вызывает обработчик функции ПРЕДСТАВЛЕНИЕ().
Простой пример поиска битых ссылок справочника "Номенклатура" во всех документах базы с табличной частью "Товары" за период.
Битая ссылка выводиться как GUID c которым дальше разбираемся как нам надо. Например - ищем в другой базе.
Битая ссылка выводиться как GUID c которым дальше разбираемся как нам надо. Например - ищем в другой базе.
Запрос = Новый Запрос;
ТекстЗапроса = "";
Для Каждого Вид Из Метаданные.Документы Цикл
ТоварыТЧ = Вид.ТабличныеЧасти.Найти("Товары");
Если ТоварыТЧ <> Неопределено Тогда
Если ТоварыТЧ.Реквизиты.Найти("Номенклатура") <> Неопределено Тогда
Если ТекстЗапроса <> "" Тогда
ТекстЗапроса=ТекстЗапроса+"
|ОБЪЕДИНИТЬ ";
КонецЕсли;
ТекстЗапроса = ТекстЗапроса+"
|ВЫБРАТЬ РАЗЛИЧНЫЕ УНИКАЛЬНЫЙИДЕНТИФИКАТОР(" + Вид.Имя + "Товары.Номенклатура) КАК GUID
|ИЗ Документ."+ Вид.Имя + ".Товары КАК " + Вид.Имя + "Товары ГДЕ
| " + Вид.Имя + "Товары.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
| И " + Вид.Имя + "Товары.Номенклатура.Ссылка ЕСТЬ NULL";
КонецЕсли;
КонецЕсли;
КонецЦикла;
Показать
Присоединяюсь к обсуждению. Столкнулся с ситуацией когда RLS обрезают права и ссылка становится битой. Для проверки использовал вот такой механизм.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ИСТИНА
|ИЗ
| Документ.РасходнаяНакладная КАК РасходнаяНакладная
|ГДЕ
| РасходнаяНакладная.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ТекущаяСтрока.РасчетныйДокумент);
Отказ = Запрос.Выполнить().Пустой();
Показать
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот