Как найти объект в базе данных 1С по его уникальному идентификатору (GUID), если тип объекта неизвестен?

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

В процессе интеграции 1С с внешними системами, загрузки файлов или автоматического создания каталогов разработчики часто сталкиваются с ситуацией, когда на диске или во внешней базе сохраняются папки и файлы, именами которых служат уникальные идентификаторы (GUID) объектов 1С. Например, имя каталога выглядит как 0ea9b930-d8a4-11e7-942b-00238b779309.

В этой статье мы подробно разберем, почему стандартные попытки получить ссылку по GUID часто приводят к ошибке <Объект не найден>, научимся расшифровывать внутренний формат хранения ссылок в 1С и реализуем универсальный алгоритм поиска любого объекта по его идентификатору, даже если мы не знаем, справочник это, документ или другой ссылочный тип.

Почему стандартный метод ПолучитьСсылку() возвращает «битую» ссылку?

Рассмотрим типичную ошибку, которую совершают многие разработчики. Полагая, что идентификатор принадлежит конкретному справочнику (например, Контрагенты), они пишут следующий код:


НовыйUID = Новый УникальныйИдентификатор(СтрокаGUID);
КонтрагентСсылка = Справочники.Контрагенты.ПолучитьСсылку(НовыйUID);

При попытке вывести полученную переменную в отчет, форму или консоль система выдает строку вида:
<Объект не найден> (32:942b00238b77930911e7d8a40ea9b930)

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

Если реальный объект с этим идентификатором на самом деле принадлежит другому типу метаданных (например, справочнику ДоговорыКонтрагентов, а не Контрагенты), либо вообще отсутствует в базе данных, то при попытке прочитать свойства этой ссылки (например, получить представление или обратиться к реквизиту Наименование) платформа обратится к СУБД, не найдет там записи в таблице контрагентов и вернет представление <Объект не найден>.

Разбор по шагам: расшифровка строки «Объект не найден»

Строка, которую возвращает платформа при невозможности прочитать объект по ссылке, содержит в себе исчерпывающую техническую информацию. Проанализируем структуру этой строки на примере:

<Объект не найден> (32:942b00238b77930911e7d8a40ea9b930)

Она состоит из двух основных частей, разделенных двоеточием внутри скобок:

  1. Внутренний код типа объекта (в данном примере — «32»): Это числовой идентификатор таблицы в базе данных 1С (так называемый ID типа). В структуре СУБД справочники хранятся в таблицах с именами вида _ReferenceN, а документы — _DocumentN, где N — это и есть наш код типа. Выяснить, какому именно объекту метаданных соответствует код 32, можно с помощью встроенной функции платформы ПолучитьСтруктуруХраненияБазыДанных().
  2. Внутренний бинарный GUID (в данном примере — «942b00238b77930911e7d8a40ea9b930»): Это тот самый 128-битный уникальный идентификатор, но записанный во внутреннем двоичном формате хранения 1С со смещением байтов.

Посмотрим на пример сопоставления исходного GUID папки и строки из системного сообщения:

Разберем алгоритм перестановки байтов, который использует платформа 1С. Разделим стандартный GUID на 5 групп символов:

A = 0ea9b930 (8 символов)
B = d8a4 (4 символа)
C = 11e7 (4 символа)
D = 942b (4 символа)
E = 00238b779309 (12 символов)

Во внутреннем представлении 1С эти блоки меняются местами по схеме: D + E + C + B + A.

Сложим их по этой схеме:

В результате склейки мы получаем точное совпадение: 942b00238b77930911e7d8a40ea9b930. Зная это правило, вы всегда можете восстановить исходный GUID из любого системного сообщения об отсутствующем объекте.

Универсальный алгоритм поиска объекта в 1С по GUID

Если у нас есть только строковое представление GUID (например, имя папки с диска), но мы не знаем, какому справочнику или документу оно принадлежит, мы можем использовать программный перебор метаданных. Ниже представлен эффективный алгоритм поиска, который последовательно обходит основные ссылочные типы данных конфигурации и проверяет физическое существование записи в базе данных.

Рассмотрим и проанализируем этот программный код:


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

Как использовать данный алгоритм на практике?

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

  1. Получаем список всех папок в целевом каталоге с помощью метода НайтиФайлы().
  2. Для каждого файла (папки) извлекаем его имя, которое представляет собой строковый GUID.
  3. Вызываем нашу функцию НайтиОбъектПоУникальномуИдентификатору(ИмяПапки).
  4. Если функция вернула ссылку, то мы определяем тип найденного объекта с помощью функции ТипЗнч(Ссылка).
  5. В зависимости от типа (например, СправочникСсылка.ДоговорыКонтрагентов или СправочникСсылка.Контрагенты) мы формируем новое понятное имя для папки. Например: ИмяПапкиНовое = Строка(Ссылка.Владелец) + " - " + Ссылка.Наименование.
  6. Используя метод ПереместитьФайл(), переименовываем нечитаемую папку на диске.

Данный подход гарантирует 100% точность сопоставления файлов с объектами базы данных 1С и позволяет быстро исправить любые ошибки интеграции или сбои в работе сторонних обработок.

← На главную