При интеграции различных информационных баз 1С с использованием технологии COM-соединения (COM-connector) разработчики часто сталкиваются с нетипичным поведением привычных типов данных. Одним из наиболее частых вопросов является передача и проверка значения Неопределено, а также определение того, существует ли конкретный объект или элемент метаданных в подключенной базе.
В рамках этой статьи мы подробно разберем, как устроена передача значения Неопределено через COM, почему стандартные проверки могут вести себя неожиданно, и как правильно искать объекты метаданных и документы в удаленной информационной базе.
Давайте заглянем под капот технологии COM-соединения. В основе COM-взаимодействия лежит передача данных через стандартную OLE-структуру VARIANT. Примитивные типы данных платформы 1С автоматически преобразуются в соответствующие типы этой структуры по следующим правилам:
NULL конвертируется в системный тип VT_NULL.Неопределено конвертируется в системный тип VT_EMPTY.Когда вызывающая («наша») база 1С принимает структуру VT_EMPTY из COM-соединения, она корректно и автоматически преобразует ее обратно в свое локальное значение Неопределено. Таким образом, на системном уровне такое значение передается без искажений.
Поэтому Неопределено из COM-базы возвращается как обычное локальное Неопределено. Проверить его можно самым простым сравнением на равенство:
Если РезультатИзCOM = Неопределено Тогда
// Выполняем действия, если значение не определено
КонецЕсли;
Проанализируем типичную ситуацию, с которой столкнулся автор темы на форуме. Разработчик пытается проверить наличие документа в удаленной базе по его имени в метаданных, используя следующую конструкцию:
Если Соединение.Метаданные.Документы.Найти(Док.Имя) <> Неопределено Тогда
// Код обработки
КонецЕсли;
В этой ситуации поведение системы может запутать начинающего программиста:
Док.Имя существует в удаленной базе, метод Найти() возвращает полноценный COM-объект (это будет ОбъектМетаданных удаленной базы). В локальном отладчике он отображается как тип COMОбъект.Неопределено.Из-за того, что при успешном поиске мы получаем сложный COMОбъект, а при неудачном — простое локальное значение, у разработчиков возникает ощущение, что и "отсутствие" должно возвращаться в виде какого-то особого COM-объекта. Но это не так: возвращается стандартное Неопределено.
Чтобы избежать путаницы с типами данных (COMОбъект против Неопределено) при поиске метаданных, мы можем применить более элегантное решение — метод Содержит(). Этот метод возвращает простое булево значение (Истина или Ложь), что полностью исключает неоднозначность типов при сравнении.
Рассмотрим пример кода для проверки существования документа в метаданных удаленной базы через метод Содержит():
ИмяДокумента = Док.Имя;
Если Соединение.Метаданные.Документы.Содержит(Соединение.Метаданные.Документы[ИмяДокумента]) Тогда
// Объект метаданных гарантированно существует в COM-базе
Иначе
// Такого документа в удаленной базе нет
КонецЕсли;
В стандартах разработки платформы 1С содержится критически важное правило: проверку переменной на тип Неопределено рекомендуется выполнять только через знак равенства (=), избегая использования знака неравенства (<>).
На некоторых релизах платформы прямое сравнение на неравенство (Значение <> Неопределено) при работе с составными типами данных или сложными COM-объектами может возвращать неверный результат (например, выдавать Ложь, даже когда переменная действительно пуста или не определена).
Если Значение <> Неопределено ТогдаЕсли Не (Значение = Неопределено) ТогдаДавайте перепишем исходную проверку автора темы с учетом этого золотого стандарта разработки:
НайденныеМетаданные = Соединение.Метаданные.Документы.Найти(Док.Имя);
Если Не (НайденныеМетаданные = Неопределено) Тогда
// Безопасный код: объект найден и мы можем с ним работать
КонецЕсли;
Часто конечная задача звучит так: "Мне нужно найти одноименные документы в подключенной базе". Разработчики пытаются найти документ по уникальному идентификатору (GUID) или коду и совершают классическую ошибку, путая системное Неопределено и пустую или несуществующую ссылку.
Представим, что мы ищем документ в COM-базе по его уникальному идентификатору:
СсылкаCOM = Соединение.Документы.РеализацияТоваровУслуг.ПолучитьСсылку(НовыйGUID);
Даже если документа с таким GUID в удаленной базе физически не существует (база абсолютно пуста), платформа 1С не вернет вам Неопределено! Она вернет полноценный COMОбъект — ссылку на несуществующий объект (так называемую "битую" ссылку).
Если вы попытаетесь проверить эту ссылку в своей локальной базе с помощью функции ЗначениеЗаполнено(СсылкаCOM), система вернет вам Истина, потому что для вашей локальной базы этот COMОбъект является заполненным дескриптором соединения!
Давайте подробно разберем три надежных метода, которые помогут вам определить, существует ли физически документ в удаленной базе.
Способ 1. Получение объекта (самый простой и надежный метод)
Если объекта с указанной ссылкой в базе нет, то попытка получить объект на стороне COM-соединения вернет чистое Неопределено. Разберем этот пример на практике:
СсылкаCOM = Соединение.Документы.РеализацияТоваровУслуг.ПолучитьСсылку(УникальныйИдентификаторДокумента);
ОбъектCOM = СсылкаCOM.ПолучитьОбъект();
Если ОбъектCOM = Неопределено Тогда
// Документ физически отсутствует в удаленной базе данных!
Иначе
// Документ найден, можно читать его реквизиты или проводить
КонецЕсли;
Способ 2. Вызов функции ЗначениеЗаполнено в контексте COM-соединения
Нельзя вызывать проверку заполненности ссылки локально в вашей базе. Но мы можем запустить глобальную функцию ЗначениеЗаполнено непосредственно в контексте удаленной базы через наше COM-соединение:
// Обратите внимание: функция вызывается как метод объекта Соединение
Если Не Соединение.ЗначениеЗаполнено(СсылкаCOM) Тогда
// Ссылка пустая или не заполнена в удаленной базе
КонецЕсли;
Способ 3. Использование функций БСП (Библиотеки Стандартных Подсистем)
Если и ваша текущая база, и удаленная база разработаны на основе БСП, то наиболее современным и производительным способом будет вызов готовой функции общего назначения удаленной базы:
Если Не Соединение.ОбщегоНазначения.СсылкаСуществует(СсылкаCOM) Тогда
// Документ не найден в удаленной базе данных
КонецЕсли;
Применяя эти проверенные методы, вы полностью застрахуете свой код от логических ошибок, связанных с обработкой пустых значений и "призрачных" объектов при интеграции систем через COM-интерфейс платформы 1С.