Как определить тип реквизита объекта метаданных при COM-соединении

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

Работа с метаданными через COM-соединение — это задача, с которой часто сталкиваются разработчики при организации обмена данными или создании универсальных инструментов мониторинга систем 1С. Основная сложность заключается в том, что объекты, передаваемые через COM-границу, ведут себя иначе, чем в родном контексте базы данных. Например, привычные функции могут возвращать неочевидный результат «COMОбъект» вместо ожидаемого имени типа. В этой статье мы подробно разберем, как эффективно определять типы реквизитов, работать с составными типами и оптимизировать этот процесс.

Проблема строкового представления типов в COM

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

Для решения этой проблемы мы должны заставить внешнюю базу саму преобразовать свой тип в строку. Рассмотрим, как это сделать правильно:


// Предположим, Соединение — это ваш установленный COM-объект
ТипРеквизита = РеквизитМетаданных.Тип.Типы()[0];
ИмяТипа = Соединение.String(ТипРеквизита);
Сообщить("Тип реквизита: " + ИмяТипа);

Метод String(), вызванный через объект соединения, принудительно выполняет преобразование на стороне источника, возвращая нам понятную строку, например, «СправочникСсылка.Номенклатура».

Метод 1: Использование коллекции метаданных и FindByType

Проанализируем наиболее распространенный способ — поиск объекта метаданных по его типу. Это позволяет получить не просто строку, а полное программное имя (FullName), которое можно использовать для дальнейших конструкций в коде. Разберем этот алгоритм по шагам:

  1. Получаем объект ОписаниеТипов реквизита.
  2. Извлекаем массив конкретных типов (так как тип может быть составным).
  3. Для каждого типа вызываем метод метаданных НайтиПоТипу().

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

Метод 2: Определение примитивных типов

Как мы выяснили выше, метод НайтиПоТипу() возвращает Неопределено для простых типов (Число, Строка, Дата, Булево). Чтобы точно идентифицировать их, мы можем сравнить тип реквизита с эталонными типами внешней базы. Рассмотрим, как программно получить эталон типа через COM:


ТипСтрока = Соединение.NewObject("ОписаниеТипов", "String").Типы()[0];
ТипЧисло  = Соединение.NewObject("ОписаниеТипов", "Number").Типы()[0];

Если ТекущийТип = ТипСтрока Тогда
    // Это строка
КонецЕсли;

Важный момент: попытка использовать локальную функцию ТипЗнч() внутри вызывающей базы для объектов из COM приведет к ошибке «Метод не обнаружен», так как это глобальная функция контекста, а не метод объекта. Всегда используйте методы через переменную соединения.

Метод 3: Использование «пустого» объекта (Лайфхак)

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


// Пример получения типа для реквизита справочника Номенклатура
НовыйЭлемент = Соединение.Справочники.Номенклатура.СоздатьЭлемент();
ИмяТипа = НовыйЭлемент.ЕдиницаИзмерения.Метаданные().ПолноеИмя();

Этот метод удобен тем, что 1С автоматически возвращает метаданные значения. Однако помните, что в случае составного типа значение реквизита в новом объекте будет равно Неопределено, и вызов Метаданные() приведет к ошибке.

Метод 4: Идентификация через XML (Универсальный подход)

Проанализируем более надежный технический способ, который не зависит от языка интерфейса или особенностей представления метаданных — использование XDTO. Метод XMLТип позволяет получить пространство имен и имя типа, которые стандартизированы в платформе.


// Получаем тип через сериализатор XDTO внешней базы
Сериализатор = Соединение.СериализаторXDTO;
ТипXML = Сериализатор.XMLТип(ТекущийТип);

Если ТипXML <> Неопределено Тогда
    Сообщить("Локальное имя XML: " + ТипXML.ИмяТипа);
    Сообщить("URI пространства имен: " + ТипXML.URIПространстваИмен);
КонецЕсли;

Этот способ незаменим при создании сложных интеграционных решений, где требуется стопроцентная точность сопоставления объектов между разными конфигурациями.

Оптимизация работы через COM

Выясним важную деталь: каждое обращение через точку в COM-соединении (например, Соединение.Метаданные.Справочники...) — это отдельный сетевой вызов (если базы на разных серверах) и серьезные затраты ресурсов на маршаллинг объектов. Если у вас сотни справочников и тысячи реквизитов, перебор их в цикле через COM будет работать крайне медленно.

Рекомендация по ускорению:

  1. Создайте во внешней базе небольшую обработку или функцию в общем модуле (если есть возможность менять конфигурацию-источник).
  2. Эта функция должна собрать всю структуру метаданных в ТаблицуЗначений или Структуру на своей стороне.
  3. Затем сериализуйте этот результат в строку JSON или XML.
  4. Передайте одну большую строку через COM и десериализуйте её локально.

Такой подход сокращает количество COM-запросов с тысяч до одного, что ускоряет получение структуры метаданных в десятки раз. Рассмотрим пример логики такой функции:


// На стороне внешней базы (в общем модуле)
Функция ПолучитьСтруктуруМетаданныхВJSON() Экспорт
    Таблица = Новый ТаблицаЗначений;
    Таблица.Колонки.Добавить("Объект");
    Таблица.Колонки.Добавить("Реквизит");
    Таблица.Колонки.Добавить("Тип");
    
    // ... логика обхода метаданных и заполнения таблицы ...
    
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, Таблица);
    Возврат ЗаписьJSON.Закрыть();
КонецФункции

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

← На главную