В процессе интеграции 1С с внешними системами, загрузки файлов или автоматического создания каталогов разработчики часто сталкиваются с ситуацией, когда на диске или во внешней базе сохраняются папки и файлы, именами которых служат уникальные идентификаторы (GUID) объектов 1С. Например, имя каталога выглядит как 0ea9b930-d8a4-11e7-942b-00238b779309.
В этой статье мы подробно разберем, почему стандартные попытки получить ссылку по GUID часто приводят к ошибке <Объект не найден>, научимся расшифровывать внутренний формат хранения ссылок в 1С и реализуем универсальный алгоритм поиска любого объекта по его идентификатору, даже если мы не знаем, справочник это, документ или другой ссылочный тип.
Рассмотрим типичную ошибку, которую совершают многие разработчики. Полагая, что идентификатор принадлежит конкретному справочнику (например, Контрагенты), они пишут следующий код:
НовыйUID = Новый УникальныйИдентификатор(СтрокаGUID);
КонтрагентСсылка = Справочники.Контрагенты.ПолучитьСсылку(НовыйUID);
При попытке вывести полученную переменную в отчет, форму или консоль система выдает строку вида:
<Объект не найден> (32:942b00238b77930911e7d8a40ea9b930)
Выясним причину такого поведения платформы. Метод ПолучитьСсылку() у менеджеров справочников и документов работает исключительно в оперативной памяти. Платформа в этот момент не делает никаких запросов к базе данных и не проверяет, существует ли физически запись с таким GUID в соответствующей таблице СУБД. Она просто генерирует ссылку указанного типа с переданным идентификатором.
Если реальный объект с этим идентификатором на самом деле принадлежит другому типу метаданных (например, справочнику ДоговорыКонтрагентов, а не Контрагенты), либо вообще отсутствует в базе данных, то при попытке прочитать свойства этой ссылки (например, получить представление или обратиться к реквизиту Наименование) платформа обратится к СУБД, не найдет там записи в таблице контрагентов и вернет представление <Объект не найден>.
Строка, которую возвращает платформа при невозможности прочитать объект по ссылке, содержит в себе исчерпывающую техническую информацию. Проанализируем структуру этой строки на примере:
<Объект не найден> (32:942b00238b77930911e7d8a40ea9b930)
Она состоит из двух основных частей, разделенных двоеточием внутри скобок:
_ReferenceN, а документы — _DocumentN, где N — это и есть наш код типа. Выяснить, какому именно объекту метаданных соответствует код 32, можно с помощью встроенной функции платформы ПолучитьСтруктуруХраненияБазыДанных().Посмотрим на пример сопоставления исходного GUID папки и строки из системного сообщения:
0ea9b930-d8a4-11e7-942b-00238b779309942b00238b77930911e7d8a40ea9b930Разберем алгоритм перестановки байтов, который использует платформа 1С. Разделим стандартный GUID на 5 групп символов:
A = 0ea9b930 (8 символов)
B = d8a4 (4 символа)
C = 11e7 (4 символа)
D = 942b (4 символа)
E = 00238b779309 (12 символов)
Во внутреннем представлении 1С эти блоки меняются местами по схеме: D + E + C + B + A.
Сложим их по этой схеме:
942b) + Блок E (00238b779309) = 942b00238b779309 (первые 16 символов значения из ошибки).11e7) + Блок B (d8a4) + Блок A (0ea9b930) = 11e7d8a40ea9b930 (последние 16 символов значения из ошибки).В результате склейки мы получаем точное совпадение: 942b00238b77930911e7d8a40ea9b930. Зная это правило, вы всегда можете восстановить исходный GUID из любого системного сообщения об отсутствующем объекте.
Если у нас есть только строковое представление GUID (например, имя папки с диска), но мы не знаем, какому справочнику или документу оно принадлежит, мы можем использовать программный перебор метаданных. Ниже представлен эффективный алгоритм поиска, который последовательно обходит основные ссылочные типы данных конфигурации и проверяет физическое существование записи в базе данных.
Рассмотрим и проанализируем этот программный код:
Функция НайтиОбъектПоУникальномуИдентификатору(Знач СтрокаGUID) Экспорт
// Проверяем корректность переданной строки
Попытка
ПоискУИД = Новый УникальныйИдентификатор(СтрокаGUID);
Исключение
ЗаписьЖурналаРегистрации("ПоискПоGUID", УровеньЖурналаРегистрации.Предупреждение, , ,
"Передан некорректный формат GUID: " + СтрокаGUID);
Возврат Неопределено;
КонецПопытки;
// Формируем массив коллекций метаданных, среди которых будем искать объект
МассивГрупп = Новый Массив;
МассивГрупп.Добавить(Справочники);
МассивГрупп.Добавить(Документы);
МассивГрупп.Добавить(ПланыВидовХарактеристик);
МассивГрупп.Добавить(ПланыСчетов);
МассивГрупп.Добавить(ПланыОбмена);
МассивГрупп.Добавить(Задачи);
МассивГрупп.Добавить(БизнесПроцессы);
// Перебираем коллекции и менеджеры объектов внутри каждой коллекции
Для Каждого Группа Из МассивГрупп Цикл
Для Каждого Менеджер Из Группа Цикл
// Получаем ссылку "в памяти" без обращения к СУБД
ТекущаяСсылка = Менеджер.ПолучитьСсылку(ПоискУИД);
// Пытаемся получить объект из базы данных.
// Именно метод ПолучитьОбъект() инициирует реальный запрос к СУБД.
Попытка
ТекущийОбъект = ТекущаяСсылка.ПолучитьОбъект();
Если ТекущийОбъект <> Неопределено Тогда
// Объект успешно найден в базе данных! Возвращаем ссылку на него.
Возврат ТекущаяСсылка;
КонецЕсли;
Исключение
// Исключение может возникнуть из-за ограничений прав доступа (RLS)
// или особенностей кастомизации конфигурации. Просто продолжаем поиск.
КонецПопытки;
КонецЦикла;
КонецЦикла;
// Если объект не найден ни в одной таблице
Возврат Неопределено;
КонецФункции
Рассмотрим практический сценарий применения функции. Представим, что нам необходимо переименовать нечитаемые каталоги на диске обратно в наименования соответствующих им договоров или контрагентов. Разберем по шагам логику нашей будущей обработки:
НайтиФайлы().НайтиОбъектПоУникальномуИдентификатору(ИмяПапки).ТипЗнч(Ссылка).СправочникСсылка.ДоговорыКонтрагентов или СправочникСсылка.Контрагенты) мы формируем новое понятное имя для папки. Например: ИмяПапкиНовое = Строка(Ссылка.Владелец) + " - " + Ссылка.Наименование.ПереместитьФайл(), переименовываем нечитаемую папку на диске.Данный подход гарантирует 100% точность сопоставления файлов с объектами базы данных 1С и позволяет быстро исправить любые ошибки интеграции или сбои в работе сторонних обработок.