Можно ли по УИД (GUID) определить тип объекта в 1С и как это сделать?

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

В практике разработчика 1С нередко возникает ситуация, когда на руках имеется лишь список уникальных идентификаторов (УИД), и необходимо понять, к каким именно данным они относятся. Например, это может быть Справочник.Номенклатура, Документ.РеализацияТоваровУслуг или любой другой объект метаданных. В этой статье мы подробно разберем, как устроены идентификаторы в системе, почему невозможно узнать тип объекта напрямую из набора символов и какие существуют стратегии решения этой задачи. Для быстрого интерактивного решения этой задачи можно применить универсальную обработку для взаимного поиска ссылок и их УИД.

Почему в УИД (GUID) изначально нет информации о типе объекта?

Для начала проанализируем техническую природу идентификатора. В платформе 1С:Предприятие используется стандарт RFC 4122 для генерации уникальных идентификаторов. Чаще всего это 128-битное число, которое в строковом виде выглядит как 3680327e-324c-11e1-80bb-0015e92c2102. Рассмотрим ключевые причины отсутствия метаданных в этой строке:

Метод 1: Программный перебор менеджеров объектов

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

Рассмотрим пример кода, который обходит справочники и пытается найти объект:


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

Функция НайтиОбъектПоСсылке(Ссылка)
    // Метод ПолучитьОбъект() или запрос - наиболее надежный способ проверки
    // Но помним, что ПолучитьОбъект() тянет все данные, это затратно.
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ " + Ссылка.Метаданные().ПолноеИмя() + " ГДЕ Ссылка = &Ссылка";
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Возврат НЕ Запрос.Выполнить().Пустой();
КонецФункции

Важный нюанс: Обратите внимание, что простое получение ссылки через ПолучитьСсылку(УИ) не обращается к базе данных. Система "соберет" ссылку в памяти, даже если объекта с таким УИД не существует. Поэтому проверка через ПолучитьОбъект() или запрос ВЫБРАТЬ Ссылка обязательна.

Метод 2: Оптимизированный поиск через пакетный запрос

Если идентификаторов много, выполнение запроса в цикле для каждого типа метаданных будет крайне медленным. Проанализируем более эффективный подход — использование оператора ОБЪЕДИНИТЬ ВСЕ. Мы можем сформировать один большой запрос, который проверит наличие ссылок сразу в нескольких вероятных таблицах. Для автоматизации этого процесса при работе с внешними файлами подойдёт инструмент для массового поиска объектов по списку уникальных идентификаторов.

Посмотрим на пример формирования такого запроса:


ТекстЗапроса = "";
Для Каждого ТипОбъекта Из СписокТипов Цикл
    Если Не ПустаяСтрока(ТекстЗапроса) Тогда
        ТекстЗапроса = ТекстЗапроса + " ОБЪЕДИНИТЬ ВСЕ ";
    КонецЕсли;
    
    ТекстЗапроса = ТекстЗапроса + 
        "ВЫБРАТЬ Ссылка, """ + ТипОбъекта + """ КАК ИмяТипа 
        |ИЗ " + ТипОбъекта + " ГДЕ Ссылка В (&МассивСсылок)";
КонецЦикла;

Такой подход сокращает количество обращений к СУБД. Однако помните, что количество соединений в одном запросе ограничено возможностями SQL-сервера, поэтому при очень большом количестве метаданных (сотни справочников и документов) запрос стоит разбивать на пачки.

Метод 3: Использование полнотекстового поиска (ПП)

Это, пожалуй, самый быстрый и современный способ найти объект, зная только строковое представление его УИД. Если в вашей базе данных включен и обновлен индекс полнотекстового поиска, система может мгновенно найти ссылку.

Алгоритм действий:

  1. Вызываем метод ПолнотекстовыйПоиск.СоздатьСписок("Тут_Ваш_УИД").
  2. Выполняем поиск методом ПерваяПорция().
  3. Если результат найден, получаем значение через Результат[0].Значение.
  4. Тип объекта определяем функцией ТипЗнч(Ссылка).

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

Метод 4: Возможности платформы 8.3.21 и выше

В новых релизах платформы (начиная с 8.3.21) работа с УИД в запросах стала значительно проще. Теперь мы можем использовать функцию УникальныйИдентификатор(Ссылка) прямо в тексте запроса. Это позволяет эффективно сопоставлять данные из внешних источников с объектами базы.

Рассмотрим пример сопоставления списка УИД из внешней таблицы значений с реальными справочниками, для ситуаций же, когда идентификаторы объектов в базах различаются и требуется сопоставление по произвольным реквизитам, используется перенос данных между похожими конфигурациями 1С:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ВТ_ВнешниеДанные.УИД КАК УИД
    |ПОМЕСТИТЬ ВТ_УИДы
    |ИЗ
    |    &ТЗ_ВнешниеДанные КАК ВТ_ВнешниеДанные
    |;
    |
    |ВЫБРАТЬ
    |    Номенклатура.Ссылка КАК Ссылка,
    |    ВТ_УИДы.УИД КАК ИсходныйУИД
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_УИДы КАК ВТ_УИДы
    |    ПО УникальныйИдентификатор(Номенклатура.Ссылка) = ВТ_УИДы.УИД";

Такая конструкция работает на уровне СУБД, что обеспечивает высокую производительность и исключает необходимость преобразования ссылок в строки на стороне сервера 1С.

Важные технические подробности (SQL и порядок байтов)

Если вы решите искать УИД напрямую в SQL-базе (например, через системные вьюхи sys.columns), важно помнить о "проблеме перепутанных байтов". 1С хранит GUID в формате Little-endian для определенных групп разрядов, что отличается от стандартного строкового представления.

При поиске в SQL строку AAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE нужно трансформировать. Первые три группы байтов (A, B и C) в бинарном поле _IDRRef хранятся в обратном порядке. Если этого не учитывать, прямой запрос к SQL-таблице по "красивой" строке УИД не вернет данных.

Подведем итоги

Мы выяснили, что "волшебной" функции, которая мгновенно скажет тип объекта по его УИД, не существует из-за архитектурных особенностей хранения данных. Однако, проанализировав ситуацию, мы можем выбрать оптимальный путь:

Всегда помните о производительности: Ссылка.ПолучитьОбъект() — это самый медленный способ проверки существования, старайтесь заменять его легкими запросами ВЫБРАТЬ 1.

← На главную