При разработке универсальных механизмов обмена данными, сравнения баз через COM-соединение или при работе с внешними источниками программисты часто сталкиваются с задачей: есть УникальныйИдентификатор (УИД) и есть информация о типе объекта, но нет прямой ссылки. Ситуация осложняется тем, что тип может быть произвольным — это может быть справочник, документ или план видов характеристик.
В этой статье мы подробно разберем, как правильно и эффективно получить ссылку в текущей базе, имея на руках только идентификатор и программно определяемый тип данных.
Рассмотрим наиболее надежный и «прозрачный» способ, основанный на анализе метаданных. Этот метод хорош тем, что он позволяет точно определить, к какой коллекции (справочники, документы и т.д.) относится объект, и безопасно обратиться к его менеджеру.
Проанализируем алгоритм решения по шагам:
Посмотрим на пример реализации такой функции:
Функция ПолучитьСсылкуПоТипуИУИД(НужныйТип, СтрокаУИД) Экспорт
// Преобразуем строку в объект УникальныйИдентификатор, если это необходимо
УидОбъекта = Новый УникальныйИдентификатор(СтрокаУИД);
// Шаг 1: Находим объект метаданных
ОбъектМетаданных = Метаданные.НайтиПоТипу(НужныйТип);
Если ОбъектМетаданных = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
// Шаг 2: Определяем имя и коллекцию
ИмяОбъекта = ОбъектМетаданных.Имя;
// Шаг 3: Динамическое обращение к менеджеру
Если Метаданные.Справочники.Содержит(ОбъектМетаданных) Тогда
Менеджер = Справочники[ИмяОбъекта];
ИначеЕсли Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда
Менеджер = Документы[ИмяОбъекта];
ИначеЕсли Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных) Тогда
Менеджер = ПланыВидовХарактеристик[ИмяОбъекта];
Иначе
// Обработка других типов (Задачи, БизнесПроцессы и т.д.)
Возврат Неопределено;
КонецЕсли;
// Получаем саму ссылку
Возврат Менеджер.ПолучитьСсылку(УидОбъекта);
КонецФункции
В данном примере мы использовали конструкцию Справочники[ИмяОбъекта]. Это обращение по индексу к коллекции менеджеров, которое позволяет избежать использования медленной функции Вычислить().
Выясним, существует ли более лаконичный способ. В платформе 1С есть мощный механизм сериализации, который можно использовать для быстрого преобразования строки УИД в ссылку, если мы знаем Тип.
Метод XMLЗначение позволяет выполнить преобразование практически в одну строку. Это особенно полезно, когда вы работаете внутри цикла и вам критична производительность.
Рассмотрим пример кода:
// Предположим, у нас есть Тип и СтрокаУИД
НужныйТип = Тип("СправочникСсылка.Контрагенты");
СтрокаУИД = "5e8e8f2e-1b7a-11eb-812d-00155d013002";
// Платформа сама найдет нужный менеджер и создаст ссылку
Ссылка = XMLЗначение(НужныйТип, СтрокаУИД);
Важный нюанс: для работы этого метода первый параметр должен быть именно типом ссылки (например, СправочникСсылка.Имя, а не просто СправочникОбъект.Имя).
Проанализируем ситуацию с перечислениями. Важно помнить, что у объектов типа Перечисление в 1С нет УИД в классическом понимании (они не хранятся в базе как GUID). Если ваше субконто или реквизит имеет тип перечисления, метод ПолучитьСсылку(УИД) не сработает.
Для работы с перечислениями при сравнении баз лучше использовать поиск по имени значения:
ИмяПеречисления = Метаданные.НайтиПоТипу(ТипЗначения).Имя;
ИмяЗначения = Строка(ЗначениеИзДругойБазы); // Получаем строковое имя
Ссылка = Перечисления[ИмяПеречисления][ИмяЗначения];
Разберем типичную ошибку: вызов Метаданные.НайтиПоТипу() внутри цикла обработки тысяч строк (например, при чтении ОСВ). Обращение к метаданным — операция ресурсоемкая.
Чтобы ускорить процесс, мы рекомендуем использовать объект Соответствие для кэширования менеджеров объектов. Это позволит выполнять поиск метаданных только один раз для каждого уникального типа.
Посмотрим, как реализовать эффективное кэширование:
КэшМенеджеров = Новый Соответствие;
Для Каждого СтрокаДанных Из ТаблицаОборотов Цикл
ТекущийТип = СтрокаДанных.ТипСубконто;
Уид = СтрокаДанных.УИД;
Менеджер = КэшМенеджеров[ТекущийТип];
Если Менеджер = Неопределено Тогда
// Определяем менеджер один раз
ОбъектМетаданных = Метаданные.НайтиПоТипу(ТекущийТип);
// ... (логика выбора коллекции из Способа 1) ...
КэшМенеджеров.Вставить(ТекущийТип, Менеджер);
КонецЕсли;
Если Менеджер <> Неопределено Тогда
Ссылка = Менеджер.ПолучитьСсылку(Новый УникальныйИдентификатор(Уид));
КонецЕсли;
КонецЦикла;
Использование кэша может ускорить выполнение обработки в десятки раз, так как исключает повторные тяжелые обращения к дереву метаданных конфигурации.
При работе с ПолучитьСсылку(УИД) нужно учитывать следующие моменты:
ПолучитьСсылку всегда возвращает объект ссылки, даже если записи с таким УИД еще нет в базе данных. Чтобы проверить, реально ли существует объект в базе, используйте метод ссылки Ссылка.ПолучитьОбъект() <> Неопределено или запрос к таблице.COM-соединение, типы данных могут передаваться как COMObject. Перед использованием НайтиПоТипу убедитесь, что вы привели тип к локальному контексту или используете строковые имена метаданных.Таким образом, мы рассмотрели основные способы динамического получения ссылок. Наиболее универсальным является сочетание метода Метаданные.НайтиПоТипу() с кэшированием менеджеров в Соответствие.