При интеграции различных информационных систем на базе 1С часто возникает задача проверки существования того или иного реквизита у объекта (документа, справочника), полученного через COM-соединение. Это критически важно при написании универсальных механизмов обмена данными, когда конфигурации источника и приемника могут различаться версиями или составом метаданных. В данной статье мы подробно разберем несколько способов решения этой задачи, проанализируем их производительность и выявим наиболее эффективные подходы.
Самый очевидный способ, который первым приходит на ум программисту 1С — это обращение к коллекции метаданных COM-объекта. Рассмотрим ситуацию, когда у нас уже установлено соединение и получен объект (например, ссылка на документ). Проанализируем программный код, позволяющий выполнить такую проверку:
// Предположим, COMСоединение уже установлено
// COMДокумент — это ссылка на объект в удаленной базе
Если COMДокумент.Метаданные().Реквизиты.Найти("Валюта") <> Неопределено Тогда
Сообщить("Реквизит 'Валюта' существует");
Иначе
Сообщить("Реквизит 'Валюта' отсутствует");
КонецЕсли;
Разберем этот пример. Мы вызываем метод Метаданные() у полученного через COM-соединение объекта. Это возвращает объект описания метаданных из удаленной базы. Далее мы обращаемся к коллекции Реквизиты и используем стандартный метод Найти().
Важное замечание: Обращение к метаданным через COM — это «дорогая» операция с точки зрения производительности. Каждый вызов через границу процессов занимает значительное время. Если вам нужно проверить реквизиты у тысячи документов в цикле, этот способ может существенно замедлить работу системы. Кроме того, помните, что коллекция Реквизиты не содержит стандартные реквизиты (такие как Дата, Номер, Проведен). Для их проверки нужно обращаться к коллекции СтандартныеРеквизиты.
Рассмотрим более изящный и быстрый способ, который основан на использовании метода ЗаполнитьЗначенияСвойств. Этот метод универсален и работает даже с COM-объектами. Основная идея заключается в создании локальной структуры с ключом, имя которого совпадает с искомым реквизитом, и уникальным начальным значением.
Проанализируем готовую функцию, которую можно использовать в своих разработках:
&НаСервере
Функция ЕстьРеквизитCOMОбъекта(COMОбъект, ИмяРеквизита) Экспорт
// Создаем уникальный маркер, которого точно не может быть в значении реквизита
Ключ = Новый УникальныйИдентификатор;
// Создаем структуру с искомым именем и нашим маркером
Структура = Новый Структура(ИмяРеквизита, Ключ);
// Пытаемся заполнить структуру из COM-объекта
ЗаполнитьЗначенияСвойств(Структура, COMОбъект);
// Если значение в структуре изменилось, значит реквизит существует и был прочитан
Возврат Структура[ИмяРеквизита] <> Ключ;
КонецФункции
Выясним причину, почему этот метод считается предпочтительным. Во-первых, он работает быстрее, чем полный разбор метаданных. Во-вторых, он одинаково успешно находит как обычные, так и стандартные реквизиты. Нам не нужно знать, к какой коллекции относится поле — ЗаполнитьЗначенияСвойств просто ищет совпадение по имени свойства объекта.
Стоит отметить технический нюанс: в некоторых случаях (особенно при использовании старых версий платформы или специфических настроек прав доступа) может потребоваться создание структуры и идентификатора на стороне COM-сервера. Тогда код будет выглядеть так:
// Где COMСоединение — объект связи с базой
COMКлюч = COMСоединение.NewObject("УникальныйИдентификатор");
COMСтруктура = COMСоединение.NewObject("Структура");
COMСтруктура.Вставить(ИмяРеквизита, COMКлюч);
COMСоединение.ЗаполнитьЗначенияСвойств(COMСтруктура, COMОбъект);
Однако в большинстве современных сценариев на платформе 8.3 достаточно локальной структуры, как показано в первом примере этого раздела.
Если нам нужно не просто проверить наличие, а сразу получить значение реквизита, если он есть, можно применить блок Попытка...Исключение. Рассмотрим этот вариант:
ЗначениеРеквизита = Неопределено;
РеквизитСуществует = Истина;
Попытка
ЗначениеРеквизита = COMОбъект.Валюта;
Исключение
РеквизитСуществует = Ложь;
КонецПопытки;
Этот метод является самым быстрым при условии, что реквизит существует в 99% случаев. Если же реквизит отсутствует часто, то генерация исключения в 1С — процедура довольно медленная, и лучше вернуться к способу со структурой.
Давайте проанализируем ситуацию и выберем лучший инструмент для каждой задачи:
Также важно помнить о различиях между V83.COMConnector и V83.Application. При использовании COMConnector взаимодействие происходит значительно быстрее, так как не инициализируется графическая оболочка удаленной базы. Все вышеперечисленные методы будут работать в обоих случаях, но для серверного кода всегда выбирайте COMConnector.
В завершение подчеркнем: при работе через COM всегда старайтесь минимизировать количество вызовов методов объекта. Если вам нужно проверить десять реквизитов, лучше создать одну структуру с десятью ключами и вызвать ЗаполнитьЗначенияСвойств один раз, чем делать это в десять подходов.