Как найти ссылку на объект в 1С по GUID, если неизвестен тип объекта?

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

В практике разработки на платформе 1С:Предприятие часто возникают задачи интеграции или восстановления данных, когда на входе мы имеем только строковое представление уникального идентификатора (GUID), но не знаем, к какому именно объекту конфигурации он относится. Это может быть справочник, документ, план видов характеристик или другой ссылочный тип. В таких случаях разработчики часто используют готовый код 1С для получения ссылки по GUID, чтобы ускорить процесс написания инструментов отладки.

Стандартные методы получения ссылки, такие как Справочники.Номенклатура.ПолучитьСсылку(), требуют явного указания менеджера объекта. Но что делать, если мы не знаем, где искать? Давайте разберем эту задачу подробно, проанализируем возможные подходы и создадим универсальный алгоритм решения.

Постановка задачи

Представим, что у нас есть строка вида "6F9619FF-8B86-D011-B42D-00CF4FC964F0". Мы знаем, что этот объект существует (или существовал) в базе данных, но не знаем, является ли он "Реализацией товаров", "Контрагентом" или "Договором". Если идентификаторов много, может потребоваться массовый поиск объектов 1С по УИН для обработки целого списка данных из внешнего файла.

Наша цель — написать функцию, которая примет на вход этот GUID и вернет реальную ссылку на объект базы данных или Неопределено, если объект не найден.

Основной подход: Перебор метаданных

Поскольку платформа 1С хранит данные в разных таблицах SQL для каждого типа объекта, нет единой команды "Найти везде". Нам придется действовать методом перебора, используя общие принципы работы с метаданными. Мы рассмотрим универсальный алгоритм поиска, который последовательно проверяет справочники и документы.

Разделим задачу на этапы:

  1. Преобразование строки в объект УникальныйИдентификатор.
  2. Перебор коллекций метаданных (Справочники, Документы и другие).
  3. Попытка получения ссылки и проверка ее существования в базе.

Реализация алгоритма поиска

Давайте напишем универсальную функцию. Для начала нам необходимо преобразовать входящую строку в тип, понятный системе.

Важный момент: Метод ПолучитьСсылку(УИД) у менеджера объекта (например, Справочники.Товары) возвращает ссылку всегда, даже если объекта с таким идентификатором нет в базе данных. Такая ссылка называется "битой" или "виртуальной". В подобных ситуациях часто применяется специальная обработка для поиска и замены битых ссылок справочников (поможет инструмент удаления битых ссылок без ТИИ). Поэтому просто получить ссылку недостаточно — нам нужно проверить, есть ли реальные данные за этой ссылкой. Для этого мы будем использовать метод ПолучитьОбъект() или запросы.

Рассмотрим код функции, которая ищет объект среди справочников и документов:


Функция НайтиСсылкуПоGUID(СтрокаGUID) Экспорт
    
    // Попытаемся создать УИД. Если строка некорректна, вернем Неопределено
    Попытка
        ИскомыйУИД = Новый УникальныйИдентификатор(СтрокаGUID);
    Исключение
        Возврат Неопределено;
    КонецПопытки;
    
    // 1. Поиск среди Справочников
    Для Каждого ОбъектМетаданных Из Метаданные.Справочники Цикл
        // Получаем менеджер справочника по имени
        Менеджер = Справочники[ОбъектМетаданных.Имя];
        
        // Получаем ссылку (она создается, даже если объекта нет)
        Ссылка = Менеджер.ПолучитьСсылку(ИскомыйУИД);
        
        // Проверяем, существует ли объект в базе
        // Метод ПолучитьОбъект() вернет Неопределено для несуществующей ссылки
        Попытка
            ОбъектБазы = Ссылка.ПолучитьОбъект();
            Если ОбъектБазы <> Неопределено Тогда
                Возврат Ссылка;
            КонецЕсли;
        Исключение
            // Игнорируем ошибки чтения, если прав недостаточно или объект битый
        КонецПопытки;
    КонецЦикла;

    // 2. Поиск среди Документов
    Для Каждого ОбъектМетаданных Из Метаданные.Документы Цикл
        Менеджер = Документы[ОбъектМетаданных.Имя];
        Ссылка = Менеджер.ПолучитьСсылку(ИскомыйУИД);
        
        Попытка
            ОбъектБазы = Ссылка.ПолучитьОбъект();
            Если ОбъектБазы <> Неопределено Тогда
                Возврат Ссылка;
            КонецЕсли;
        Исключение
        КонецПопытки;
    КонецЦикла;
    
    // Если ничего не нашли
    Возврат Неопределено;

КонецФункции

Оптимизация производительности: Использование запроса

Метод ПолучитьОбъект() считывает весь объект целиком в память. Если у нас "тяжелые" документы с тысячами строк в табличных частях, такой перебор может работать медленно. Более производительным способом является проверка существования ссылки через `Запрос`. В запросе мы можем выбрать только поле Ссылка, что значительно снизит нагрузку на систему.

Давайте оптимизируем наш алгоритм, используя запросы для проверки:


Функция НайтиСсылкуПоGUID_ЧерезЗапрос(СтрокаGUID) Экспорт
    
    Попытка
        ИскомыйУИД = Новый УникальныйИдентификатор(СтрокаGUID);
    Исключение
        Возврат Неопределено;
    КонецПопытки;
    
    // Список коллекций для поиска
    МассивКоллекций = Новый Массив;
    МассивКоллекций.Добавить("Справочник");
    МассивКоллекций.Добавить("Документ");
    МассивКоллекций.Добавить("ПланВидовХарактеристик");
    // Можно добавить ПланСчетов, ПланОбмена и т.д.
    
    Для Каждого ВидМетаданных Из МассивКоллекций Цикл
        
        // Получаем коллекцию метаданных через глобальный контекст Метаданные
        Если ВидМетаданных = "Справочник" Тогда
            КоллекцияМД = Метаданные.Справочники;
        ИначеЕсли ВидМетаданных = "Документ" Тогда
            КоллекцияМД = Метаданные.Документы;
        ИначеЕсли ВидМетаданных = "ПланВидовХарактеристик" Тогда
            КоллекцияМД = Метаданные.ПланыВидовХарактеристик;
        Иначе
            Продолжить;
        КонецЕсли;
            
        Для Каждого МД Из КоллекцияМД Цикл
            
            ИмяТаблицы = ВидМетаданных + "." + МД.Имя;
            
            // Формируем текст запроса динамически
            ТекстЗапроса = 
            "ВЫБРАТЬ ПЕРВЫЕ 1
            |   Таблица.Ссылка КАК Ссылка
            |ИЗ
            |   " + ИмяТаблицы + " КАК Таблица
            |ГДЕ
            |   Таблица.Ссылка = &Ссылка";
            
            // Получаем "предполагаемую" ссылку через менеджер
            Если ВидМетаданных = "Справочник" Тогда
                СсылкаПоиска = Справочники[МД.Имя].ПолучитьСсылку(ИскомыйУИД);
            ИначеЕсли ВидМетаданных = "Документ" Тогда
                СсылкаПоиска = Документы[МД.Имя].ПолучитьСсылку(ИскомыйУИД);
            ИначеЕсли ВидМетаданных = "ПланВидовХарактеристик" Тогда
                СсылкаПоиска = ПланыВидовХарактеристик[МД.Имя].ПолучитьСсылку(ИскомыйУИД);
            КонецЕсли;
            
            Запрос = Новый Запрос;
            Запрос.Текст = ТекстЗапроса;
            Запрос.УстановитьПараметр("Ссылка", СсылкаПоиска);
            
            // Если запрос вернул результат - объект найден в БД
            Если Не Запрос.Выполнить().Пустой() Тогда
                Возврат СсылкаПоиска;
            КонецЕсли;
            
        КонецЦикла;
    КонецЦикла;
    
    Возврат Неопределено;

КонецФункции

Расширение области поиска

В приведенных примерах мы рассматривали только справочники и документы. Однако в реальных базах ссылки могут принадлежать и другим объектам. Основные коллекции метаданных:

Рекомендации по применению

Важно понимать, что поиск перебором — это ресурсоемкая операция. Если в вашей конфигурации сотни видов документов и справочников, выполнение такого кода может занять ощутимое время.

Советы для оптимизации:

  1. Если вы примерно знаете область поиска (например, только документы торговли), ограничьте перебор по подсистемам или префиксам имен.
  2. Используйте этот алгоритм только в исключительных случаях (администрирование, разовая загрузка), избегайте его использования в транзакциях и часто вызываемых процедурах.
  3. Если задача поиска стоит регулярно, рассмотрите возможность создания регистра сведений для кэширования соответствий, где будет храниться `GUID` -> `ЛюбаяСсылка`.
  4. При работе с внешними ссылками вам может помочь получение ссылки из навигационной ссылки (для этого подойдет расширение для распознавания навигационных ссылок), что избавляет от необходимости ручного поиска GUID.

Таким образом, мы выяснили, что даже не зная типа объекта, можно найти его в базе, используя возможности метаданных и динамическое формирование запросов. Это мощный инструмент для системного программиста 1С, позволяющий решать сложные задачи по диагностике данных.

← На главную