Как программно получить менеджер объекта из ссылки или реквизита в 1С

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

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

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

Представим ситуацию: у нас есть объект (например, «Номенклатура»), в котором присутствует реквизит Реквизит1. Тип этого реквизита — СправочникСсылка.ЦеновыеГруппы. Наша цель — получить объект СправочникМенеджер.ЦеновыеГруппы, имея на руках только саму ссылку или описание типа этого реквизита. Это необходимо для того, чтобы программно присвоить реквизиту новую ссылку, созданную на основании GUID.

Способ 1. Использование коллекций через имя метаданных

Проанализируем самый простой и очевидный способ. У любого ссылочного значения есть свойство Метаданные(), которое позволяет узнать имя объекта. Зная имя и понимая, что перед нами (справочник или документ), мы можем обратиться к глобальной коллекции.

Рассмотрим пример кода:


// Допустим, СсылкаНаОбъект — это наше значение из реквизита
ИмяОбъекта = СсылкаНаОбъект.Метаданные().Имя;
// Если мы уверены, что это справочник:
Менеджер = Справочники[ИмяОбъекта];

Однако этот метод перестает работать, если тип объекта заранее неизвестен (это может быть и Документ, и ПланВидовХарактеристик). В таком случае нам придется «угадывать» коллекцию.

Способ 2. Универсальный перебор типов (Если...ИначеЕсли)

Чтобы сделать код по-настоящему универсальным и избежать ошибок, мы можем использовать проверку на принадлежность типа к системным коллекциям «ВсеСсылки». Это надежный способ, который охватывает почти все возможные метаданные.

Разберем по шагам создание такой функции:


Функция ПолучитьМенеджерПоСсылке(Ссылка)
    МетаданныеОбъекта = Ссылка.Метаданные();
    ИмяОбъекта = МетаданныеОбъекта.Имя;
    ТипСсылки = ТипЗнч(Ссылка);

    Если Справочники.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
        Возврат Справочники[ИмяОбъекта];
    ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
        Возврат Документы[ИмяОбъекта];
    ИначеЕсли ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
        Возврат ПланыВидовХарактеристик[ИмяОбъекта];
    ИначеЕсли Задачи.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
        Возврат Задачи[ИмяОбъекта];
    ИначеЕсли БизнесПроцессы.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
        Возврат БизнесПроцессы[ИмяОбъекта];
    Иначе
        Возврат Неопределено;
    КонецЕсли;
КонецФункции

Преимущество: этот метод работает максимально прозрачно и не использует «магических» преобразований строк.

Способ 3. Использование оператора Новый() и полного имени

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

Проанализируем ситуацию: полное имя метаданных справочника выглядит как Справочник.Номенклатура. Системное имя его менеджера — СправочникМенеджер.Номенклатура. Мы можем просто заменить точку на слово «Менеджер».


ПолноеИмяМетаданных = Ссылка.Метаданные().ПолноеИмя(); // Получим "Справочник.ЦеновыеГруппы"
ИмяТипаМенеджера = СтрЗаменить(ПолноеИмяМетаданных, ".", "Менеджер."); // Станет "СправочникМенеджер.ЦеновыеГруппы"
Менеджер = Новый(ИмяТипаМенеджера);

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

Способ 4. Библиотека стандартных подсистем (БСП)

Если ваша конфигурация построена на базе БСП (а это почти все современные решения: ERP, УТ 11, БП 3.0), то разработчики уже написали за вас все необходимые функции. В модуле ОбщегоНазначения есть готовые инструменты.

Посмотрим на пример использования:


// Получение менеджера одной строкой
Менеджер = ОбщегоНазначения.МенеджерОбъектаПоСсылке(СсылкаРеквизита);

Если же вам нужно сразу получить ссылку по ГУИДу, не заботясь о менеджере, можно воспользоваться другим методом:


// СсылкаИнформационнойБазы принимает тип или полное имя и сам GUID
НоваяСсылка = ОбщегоНазначения.СсылкаИнформационнойБазы(ТипЗнч(Реквизит1), НужныйУИД);

Это считается «лучшей практикой» (best practice), так как код получается коротким и легко читаемым.

Способ 5. Определение типа через XMLТип

Выясним причину, почему иногда стандартные методы метаданных могут быть медленными. При работе с тысячами объектов в цикле обращение к Метаданные() создает нагрузку. В таких случаях можно использовать функцию XMLТип, которая возвращает структуру с описанием типа без глубокого анализа дерева метаданных.


ДанныеXML = XMLТип(ТипЗнч(Ссылка));
// ДанныеXML.ИмяТипа вернет строку вида "CatalogRef.ЦеновыеГруппы"
// Далее логика аналогична способу №3

Проблема пустых ссылок

Рассмотрим важный нюанс: что делать, если в реквизите Реквизит1 еще нет значения (пустая ссылка)? Если мы попытаемся вызвать Объект.Реквизит1.Метаданные(), мы получим метаданные типа, но если реквизит имеет составной тип и он не заполнен, программа может повести себя непредсказуемо.

Для гарантированного получения метаданных по типу (даже если ссылки нет) лучше использовать метод:

МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(НужныйОбъект));

Итоговый алгоритм решения задачи

Подводя итог, разберем по шагам, как должна выглядеть идеальная процедура установки ссылки по ГУИД для произвольного реквизита:

  1. Определяем Тип значения, которое должно храниться в реквизите.
  2. Находим Метаданные этого типа через Метаданные.НайтиПоТипу().
  3. Формируем имя менеджера или используем БСП.
  4. Получаем Менеджер.
  5. Вызываем Менеджер.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаГруппы)).
  6. Присваиваем результат реквизиту объекта.

Совет по производительности: если вы делаете это в цикле обработки данных, обязательно кэшируйте менеджеры в переменную типа Соответствие. Ключом будет Тип, а значением — полученный Менеджер. Это ускорит работу вашего кода в десятки раз за счет исключения повторных обращений к метаданным.

Таким образом, мы проанализировали ситуацию и выяснили, что наиболее универсальным и современным способом является использование методов БСП или конструктора Новый() со строковой подстановкой. Это делает код устойчивым к изменениям в структуре метаданных и легким для поддержки другими разработчиками.

← На главную