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

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

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

В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем типичные ошибки разработчиков и рассмотрим пять надежных и производительных способов работы с перечислениями через COM-соединение в 1С:Предприятии 8.3.

Почему возникает ошибка при работе с перечислениями через COM?

Для начала выясним причину, по которой простые методы сравнения и присвоения дают сбой. Когда мы обращаемся к внешней базе через COMConnector, все возвращаемые объекты являются прокси-объектами типа COMОбъект.

Посмотрим на типичную ошибку при сравнении объектов:


Если Строка(Стр.Ссылка) = Строка(Выборка.Ссылка[строка.РеквезитВторойБазы]) Тогда
    // Код не выполнится корректно
КонецЕсли;

В данном сценарии функция Строка() выполняется в контексте локальной базы. Для внешнего COM-объекта она вернет системное строковое представление вида "COM-объект". В итоге условие превратится в сравнение "COM-объект" = "COM-объект", что всегда будет давать истину, независимо от реального значения перечисления. Это приводит к некорректной записи данных.

Теперь рассмотрим правильные, протестированные практикой подходы к решению этой задачи.

Способ 1. Использование функции "ПредопределенноеЗначение" через COM (Самый чистый способ)

Начиная с платформы 1С 8.2, в системе доступна глобальная функция ПредопределенноеЗначение(). Она прекрасно работает и во внешнем COM-соединении. Этот метод является наиболее лаконичным, производительным и безопасным, так как не требует ручного поиска в метаданных или написания запросов.

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


// Создаем элемент справочника во второй базе через COM
НовСправочник = ComObject.Справочники.Номенклатура.СоздатьЭлемент();

// Устанавливаем перечисление СтавкиНДС напрямую с помощью ПредопределенноеЗначение
НовСправочник.СтавкаНДС = ComObject.ПредопределенноеЗначение("Перечисление.СтавкиНДС.НДС18");
НовСправочник.Записать();

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

Способ 2. Использование метода XMLString (Универсальный строковый метод)

Метод XMLString() является аналогом локальной функции XMLСтрока(), но вызывается в контексте COM-соединения. Для перечислений этот метод возвращает строковое имя значения (имя из конфигуратора, например, "НДС18"). Это позволяет легко сопоставлять перечисления между базами.

Сценарий А: Получение значения из COM-базы и поиск аналога в локальной базе


// Получаем COM-значение перечисления из внешней базы
COMЗначение = ВыборкаИзCOM.СтавкаНДС;

// Получаем строковое имя значения (например, "НДС18")
ИмяЗначения = ComObject.XMLString(COMЗначение);

// Записываем значение в локальный справочник
ЛокальныйСправочник.СтавкаНДС = Перечисления.СтавкиНДС[ИмяЗначения];

Сценарий Б: Запись значения в COM-базу по локальному значению


// Получаем имя локального перечисления
ИмяЛокальногоЗначения = XMLСтрока(ЛокальныйСправочник.СтавкаНДС);

// Записываем во внешнюю базу через квадратные скобки
НовСправочник.СтавкаНДС = ComObject.Перечисления.СтавкиНДС[ИмяЛокальногоЗначения];

Способ 3. Синхронизация по индексу значения (Самый быстрый способ)

Каждое значение перечисления в 1С имеет свой порядковый номер — индекс (начиная с 0), соответствующий его расположению в конфигураторе. Если структуры перечислений в обеих базах идентичны, мы можем сопоставлять их по числовому индексу. Это избавляет от строковых операций и работает максимально быстро.

Перенос значения из COM-базы в локальную:


// Получаем числовой индекс значения во внешней базе
ИндексВCOM = ComObject.Перечисления.СтавкиНДС.Индекс(COMЗначениеПеречисления);

// Находим локальное значение по полученному индексу
ЛокальноеЗначение = Перечисления.СтавкиНДС.Получить(ИндексВCOM);

Перенос значения из локальной базы в COM-базу:


// Получаем локальный индекс
ИндексЛокальный = Перечисления.СтавкиНДС.Индекс(ЛокальноеЗначение);

// Находим значение в COM-базе по индексу
НовСправочник.СтавкаНДС = ComObject.Перечисления.СтавкиНДС.Получить(ИндексЛокальный);

Важное предупреждение: Используйте этот метод только в том случае, если вы абсолютно уверены, что состав и порядок значений перечисления в обеих конфигурациях полностью совпадают.

Способ 4. Получение синонима через метод String()

Иногда требуется сопоставить значения по их пользовательскому представлению (синониму), например, когда имена в конфигураторе различаются, но синонимы одинаковы (например, "Без НДС"). Для корректного получения представления COM-объекта необходимо использовать метод String() самого COM-соединения.

Проанализируем следующий пример кода:


// Получаем текстовое представление значения из COM-базы
ПредставлениеCOM = ComObject.String(COMЗначениеПеречисления); // Вернет, например, "18%"

// Выполняем поиск по представлению в локальной базе
Для Каждого ЗначениеИзПеречисления Из Перечисления.СтавкиНДС Цикл
    Если Строка(ЗначениеИзПеречисления) = ПредставлениеCOM Тогда
        ЛокальныйСправочник.СтавкаНДС = ЗначениеИзПеречисления;
        Прервать;
    КонецЕсли;
КонецЦикла;

Способ 5. Использование запросов для массовой обработки

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

Разберем эффективный алгоритм:


// Создаем объект Запрос во внешней базе
ЗапросCOM = ComObject.NewObject("Запрос");
ЗапросCOM.Текст = 
    "ВЫБРАТЬ
    |	СтавкиНДС.Ссылка КАК Ссылка,
    |	Порядок(СтавкиНДС) КАК Порядок
    |ИЗ
    |	Перечисление.СтавкиНДС КАК СтавкиНДС";

ТаблицаЗначенийCOM = ЗапросCOM.Выполнить().Выгрузить();

// Теперь мы можем быстро обойти коллекцию на клиенте/сервере локальной базы
Для Каждого СтрокаCOM Из ТаблицаЗначенийCOM Цикл
    // Получаем имя значения перечисления через XMLString для сопоставления
    ИмяЗначения = ComObject.XMLString(СтрокаCOM.Ссылка);
    
    // Выполняем сопоставление с локальным перечислением
    Попытка
        ЛокальноеЗначение = Перечисления.СтавкиНДС[ИмяЗначения];
        // Выполняем дальнейшую обработку...
    Исключение
        // Обработка ситуации, если в локальной базе нет такого значения
    КонецПопытки;
КонецЦикла;

Рекомендации для стабильной работы

  1. Избегайте прямого сравнения: Никогда не сравнивайте ссылочные COM-объекты напрямую оператором = в локальном коде. Сравнивайте либо их индексы, либо строковые имена, полученные через ComObject.XMLString().
  2. Используйте кэширование: Если вы часто обращаетесь к перечислениям внешней базы в цикле, кэшируйте полученные значения в локальное соответствие (коллекцию Соответствие), чтобы не выполнять ресурсоемкие COM-вызовы повторно.
  3. Выбирайте правильный способ подключения: Для фоновых задач обмена данными лучше использовать тонкое соединение V83.COMConnector, так как оно работает значительно быстрее, чем запуск полноценного приложения V83.Application.
← На главную