Как получить тип ДокументОбъект из ссылки без считывания объекта из базы данных?

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

При разработке алгоритмов в 1С часто возникает задача определить тип объекта прикладного решения (например, ДокументОбъект.ПриходнаяНакладная), имея на руках только ссылку (ДокументСсылка.ПриходнаяНакладная). Классический и самый простой вариант — вызвать ТипЗнч(Ссылка.ПолучитьОбъект()). Однако такой подход категорически не рекомендуется использовать в высоконагруженных сценариях, таких как обработчики записи регистров.

Рассмотрим, почему вызов ПолучитьОбъект() негативно влияет на производительность, и разберем по шагам правильные и быстрые способы получения типа объекта через метаданные платформы 1С:Предприятие.

Почему нельзя использовать ПолучитьОбъект() для проверки типа?

Проанализируем техническую сторону работы метода ПолучитьОбъект():

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

Если цель проверки — лишь узнать тип объекта (например, чтобы проверить, является ли регистратор источником конкретной подписки на события), считывать сам объект из базы совершенно не требуется.

Способ 1. Формирование типа через метаданные документа

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

Посмотрим на пример реализации:


Если Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(ДокСсылка)) Тогда
    ИмяМетаданных = ДокСсылка.Метаданные().Имя;
    ТипОбъекта = Тип("ДокументОбъект." + ИмяМетаданных);
КонецЕсли;

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

Способ 2. Универсальное получение типа объекта для любых ссылок

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

Используем метод Метаданные.НайтиПоТипу():


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

Если ОбъектМетаданных <> Неопределено Тогда
    // Заменяем первую точку в полном имени (например, "Документ.РеализацияТоваровУслуг" -> "ДокументОбъект.РеализацияТоваровУслуг")
    ИмяТипаОбъекта = СтрЗаменить(ОбъектМетаданных.ПолноеИмя(), ".", "Объект.");
    ТипОбъекта = Тип(ИмяТипаОбъекта);
КонецЕсли;

Преимущества такого подхода:

  1. Безопасность: Если в переменную попадет Неопределено, Null или число, Метаданные.НайтиПоТипу() вернет Неопределено, не вызывая исключения.
  2. Универсальность: Преобразование одинаково корректно отрабатывает для справочников (СправочникОбъект), документов (ДокументОбъект), планов счетов и других ссылочных типов.

Способ 3. Проверка типа в источнике подписки на события

Если задача заключается именно в проверке наличия объекта в подписке на события, выясним особенности работы с метаданными подписок.

Свойство Источник у объекта метаданных подписки возвращает ОписаниеТипов. Проверить, подходит ли полученный тип объекта подписки, можно напрямую методом СодержитТип():


ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
Если ОбъектМетаданных <> Неопределено Тогда
    ТипОбъекта = Тип(СтрЗаменить(ОбъектМетаданных.ПолноеИмя(), ".", "Объект."));
    
    // Получаем подписку на событие из метаданных
    Подписка = Метаданные.ПодпискиНаСобытия.Найти("ПередЗаписьюДокумента");
    
    Если Подписка <> Неопределено И Подписка.Источник.СодержитТип(ТипОбъекта) Тогда
        // Тип объекта зарегистрирован в качестве источника для данной подписки
    КонецЕсли;
КонецЕсли;

Рекомендации по оптимизации производительности

Рассмотрим важные нюансы при работе в высоконагруженных участках кода:

  1. Кэширование результатов: Операции с метаданными и вызовы функций Тип() или СтрЗаменить() в теле больших циклов создают дополнительные накладные расходы. Рекомендуется сохранять соответствие ТипСсылки -> ТипОбъекта или готовый список поддерживаемых типов в модуль с повторным использованием значений или во внутреннюю структуру кэша.
  2. Программный вызов обработчика: Помните, что обработчики событий подписок рассчитаны на получение самого объекта в качестве параметра. Если логика обработчика требует чтения полей документа, избежать вызова ПолучитьОбъект() на этапе выполнения самого алгоритма не удастся, однако предварительную фильтрацию по типам всегда следует делать описанным выше легковесным способом.
← На главную