При интеграции двух информационных баз 1С с использованием COM/OLE-соединения часто возникает необходимость программно анализировать типы реквизитов объектов: как в метаданных конфигурации-источника, так и у фактически полученных данных. При этом разработчики сталкиваются с тем, что стандартные локальные конструкции вроде ТипЗнч() или метод СодержитТип() ведут себя неожиданно: возвращают тип COMОбъект или всегда дают результат Ложь. Разберем детально, почему это происходит и какими способами можно корректно определить типы реквизитов через внешнее соединение.
Чтобы понять логику работы платформы, проанализируем ключевые особенности маршалинга данных и контекстов исполнения:
Тип("Строка") не равен объекту типа Строка, созданному в удаленной базе. Из-за этого вызов метода ОписаниеТипов.СодержитТип(Тип("Строка")) вернет Ложь, так как проверяемый тип передан из локального контекста, а не из удаленного.Тип маршалируются как непрозрачные COMОбъект.ТипЗнч() к объекту метаданных или описанию типа из внешней базы, платформа вернет тип локальной обертки — COMОбъект.Рассмотрим наиболее универсальный и надежный подход к определению типов реквизита в метаданных внешней базы — использование функции XMLТип, вызванной в контексте внешнего соединения. Этот метод позволяет получить каноническое строковое имя типа (как для примитивных, так и для ссылочных типов данных).
Разберем по шагам реализацию данного алгоритма:
// Получаем реквизит метаданных из внешней базы
РеквизитМетаданных = СоединениеCOM.Метаданные.Справочники.Номенклатура.Реквизиты.Артикул;
ОписаниеТиповCOM = РеквизитМетаданных.Тип;
// Получаем массив типов, входящих в описание типов
МассивТиповCOM = ОписаниеТиповCOM.Типы();
Для Индекс = 0 По МассивТиповCOM.Количество() - 1 Цикл
ТекТипCOM = МассивТиповCOM.Получить(Индекс);
// Вызываем функцию XMLТип строго в контексте внешнего соединения
ТипXML = СоединениеCOM.XMLТип(ТекТипCOM);
ИмяТипа = ТипXML.ИмяТипа; // Вернет "string", "decimal", "CatalogRef.Контрагенты" и т.д.
URIТипа = ТипXML.URIПространстваИмен; // Пространство имен XSD или схемы 1С
КонецЦикла;
Такой подход исключает ошибки несовместимости типов между различными базами и позволяет однозначно сопоставить типы данных.
Если требуется проверить наличие конкретного типа в описании типов реквизита (например, проверить, может ли реквизит принимать строковое значение), необходимо передавать в метод СодержитТип() объект типа, полученный именно из COM-соединения.
Посмотрим на пример кода:
РеквизитМетаданных = СоединениеCOM.Метаданные.Справочники.Контрагенты.Реквизиты.ИНН;
ОписаниеТиповCOM = РеквизитМетаданных.Тип;
// Получаем объект типа из контекста COM-соединения
ТипСтрокаCOM = СоединениеCOM.Тип("Строка");
Если ОписаниеТиповCOM.СодержитТип(ТипСтрокаCOM) Тогда
// Реквизит поддерживает тип "Строка"
КонецЕсли;
Также строковое представление типа из удаленной базы можно получить через метод преобразования строки внешнего соединения:
ИмяТипаСтрокой = СоединениеCOM.String(ТекТипCOM); // Вернет строковое представление, например "Строка" или "Число"
В ситуациях, когда необходимо анализировать не структуру метаданных, а уже прочитанный объект или выборку данных, логика проверки разделяется в зависимости от природы данных:
ЗначениеРеквизита = ОбъектCOM.Наименование;
Если ТипЗнч(ЗначениеРеквизита) = Тип("Строка") Тогда
// Обработка строкового значения
КонецЕсли;
COMОбъект. Чтобы выяснить его конкретный тип, следует запросить метаданные самой ссылки через COM:
ЗначениеСсылки = ОбъектCOM.ОсновнойДоговор;
Если ЗначениеСсылки <> Неопределено И ЗначениеСсылки <> Null Тогда
ПолноеИмяТипа = ЗначениеСсылки.Метаданные().ПолноеИмя(); // Вернет, например, "Справочник.ДоговорыКонтрагентов"
КонецЕсли;
XMLТипЗнч:
ТипXML = СоединениеCOM.XMLТипЗнч(ОбъектCOM.Реквизит);
Если ТипXML <> Неопределено Тогда
ИмяТипа = ТипXML.ИмяТипа;
КонецЕсли;
Важное правило: все операции по анализу типов метаданных (Метаданные(), ОписаниеТипов, Тип(), XMLТип()) должны выполняться в контексте того COM-соединения, из которого эти объекты получены.