Как правильно сравнивать значения перечислений и ссылки через COM-соединение в 1С?

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

При интеграции двух информационных баз 1С с использованием COM-соединения разработчики часто сталкиваются с неожиданным поведением платформы: при попытке сравнить через оператор = реквизит внешнего объекта со значением перечисления или со ссылкой справочника из внешней базы результат всегда равен Ложь.

Проанализируем типичный пример ошибочного кода:


// Попытка прямого сравнения перечисления
Если СкладВПриемнике.ВидСклада = мВнешнееСоединение.Перечисления.ВидыСкладов.Розничный Тогда
    // Данный блок никогда не выполнится
КонецЕсли;

Выясним причину такого поведения и подробно разберем все способы решения этой задачи.

Почему прямое сравнение возвращает Ложь?

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

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

Способ 1. Использование объекта «СравнениеЗначений» (рекомендуемый универсальный способ)

Наиболее лаконичным и корректным решением является использование встроенного объекта платформы СравнениеЗначений, созданного непосредственно в контексте внешнего соединения. Поскольку объект создается во внешней базе, он выполняет сравнение по правилам платформы 1С.

Посмотрим на пример сравнения перечислений и ссылок:


// Создаем объект сравнения в контексте внешней базы
Сравнение = мВнешнееСоединение.NewObject("СравнениеЗначений");

// Сравнение перечисления
ЗначениеПеречисления = мВнешнееСоединение.Перечисления.ВидыСкладов.Розничный;
Если Сравнение.Сравнить(СкладВПриемнике.ВидСклада, ЗначениеПеречисления) = 0 Тогда
    Сообщить("Вид склада соответствует розничному!");
КонецЕсли;

// Сравнение ссылок справочников
Ссылка1 = мВнешнееСоединение.Справочники.Организации.НайтиПоКоду("000000001");
Ссылка2 = СкладВПриемнике.Организация;
Если Сравнение.Сравнить(Ссылка1, Ссылка2) = 0 Тогда
    Сообщить("Организации совпадают!");
КонецЕсли;

Метод Сравнить возвращает 0, если переданные значения равны.

Способ 2. Сравнение канонических имен через XMLСтрока

Часто разработчики применяют преобразование в строку через функцию String(). Однако строковое представление возвращает синоним (пользовательское представление), которое может измениться при обновлении конфигурации или смене языка интерфейса. Надежнее использовать метод XMLСтрока внешнего соединения, который возвращает фиксированное имя идентификатора значения перечисления в метаданных.

Разберем реализацию:


// Получаем каноническое имя значения перечисления
ИмяЗначения = мВнешнееСоединение.XMLСтрока(СкладВПриемнике.ВидСклада);

Если ИмяЗначения = "Розничный" Тогда
    Сообщить("Склад является розничным");
КонецЕсли;

Способ 3. Выполнение запроса в COM-соединении

Если требуется обработать большой объем данных или проверить условия для множества объектов, поштучное обращение через COM создает значительные накладные расходы. В таких сценариях эффективнее выполнять проверку через объект Запрос во внешней базе.

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


Запрос = мВнешнееСоединение.NewObject("Запрос");
Запрос.Текст = 
"ВЫБРАТЬ
|   Склады.Ссылка КАК Ссылка
|ИЗ
|   Справочник.Склады КАК Склады
|ГДЕ
|   Склады.Ссылка = &СсылкаНаСклад
|   И Склады.ВидСклада = ЗНАЧЕНИЕ(Перечисление.ВидыСкладов.Розничный)";

Запрос.УстановитьПараметр("СсылкаНаСклад", СкладВПриемнике.Ссылка);
Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
    Сообщить("Склад найден и он розничный");
КонецЕсли;

Способ 4. Сравнение ссылочных объектов по Уникальному Идентификатору

Для справочников, документов и других объектов, обладающих GUID (в отличие от перечислений), можно сравнивать строковые представления их уникальных идентификаторов:


ГУИД1 = мВнешнееСоединение.String(Ссылка1.УникальныйИдентификатор());
ГУИД2 = мВнешнееСоединение.String(Ссылка2.УникальныйИдентификатор());

Если ГУИД1 = ГУИД2 Тогда
    Сообщить("Ссылки указывают на один и тот же элемент");
КонецЕсли;

Способ 5. Сравнение по индексу значения перечисления

Если необходимо проверить позицию значения в перечислении, можно использовать метод менеджера перечисления Индекс():


Менеджер = мВнешнееСоединение.Перечисления.ВидыСкладов;
ИндексТекущий = Менеджер.Индекс(СкладВПриемнике.ВидСклада);
ИндексЭталон = Менеджер.Индекс(Менеджер.Розничный);

Если ИндексТекущий = ИндексЭталон Тогда
    Сообщить("Индексы совпадают");
КонецЕсли;

Подведем итог: для точечного сравнения значений без изменения конфигурации внешней базы оптимально использовать СравнениеЗначений или XMLСтрока, а при массовой обработке данных — встроенный механизм Запросов.

← На главную