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

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

При разработке механизмов обмена данными между двумя информационными базами 1С с использованием технологии COM-соединения (V83.COMConnector или V83.Application) программисты часто сталкиваются с проблемой передачи ссылочных типов. Если передача строк, чисел и дат проходит бесшовно, то при попытке напрямую присвоить значение перечисления из одной базы реквизиту объекта в другой базе возникает ошибка или значение попросту не устанавливается. Это происходит потому, что перечисление является сложным типом (ссылкой), а через COM-интерфейс корректно передаются только примитивные типы данных.

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

Причина проблемы: Почему прямое присвоение не работает?

Рассмотрим стандартную ситуацию. У нас есть «База А» (текущая) и «База Б» (подключенная через COM). Мы пытаемся выполнить следующий код:


// В Базе А
ОбъектБазыБ = БазаБ.Справочники.Номенклатура.СоздатьЭлемент();
ОбъектБазыБ.Наименование = "Новый товар";
// Попытка прямого присвоения перечисления
ОбъектБазыБ.Статус = Перечисления.СтатусыНоменклатуры.Активен; 
ОбъектБазыБ.Записать();

В данном примере Перечисления.СтатусыНоменклатуры.Активен — это объект «Базы А». Для «Базы Б» этот объект является чужеродным, она «не понимает» его внутренний идентификатор. Чтобы успешно установить значение, нам нужно передать примитив (строку или число), по которому «База Б» сама найдет нужное значение в своем пространстве имен.

Способ 1. Поиск по строковому имени (Идентификатору)

Это один из самых распространенных и понятных способов. Мы передаем в подключаемую базу строковое имя значения перечисления, которое задано в конфигураторе. Важно понимать разницу между Синонимом (то, что видит пользователь) и Именем (то, что написано в дереве метаданных).

Рассмотрим реализацию, предложенную участниками форума:


// Выборка — это результат запроса или объект из текущей базы
// База — это установленное COM-соединение
СтроковоеЗначение = Строка(Выборка.ЕдИзм);
ОбъектБазы.ЕдИзм = База.Перечисления["ЕдИзм"][СтроковоеЗначение];

Важное замечание: Метод Строка() вернет синоним. Если синоним значения «Штука» в базе — «шт.», то код попытается найти значение с именем «шт.», что приведет к ошибке, если имя в конфигураторе — «Штука». Поэтому для надежности лучше использовать обращение через метаданные для получения точного программного имени.


ИмяЗначения = Метаданные.Перечисления.ЕдИзм.ЗначенияПеречисления[Перечисления.ЕдИзм.Индекс(Выборка.ЕдИзм)].Имя;
ОбъектБазы.ЕдИзм = База.Перечисления.ЕдИзм[ИмяЗначения];

Способ 2. Использование индекса значения

Если структуры метаданных в обеих базах гарантированно идентичны (одинаковый состав и порядок значений перечисления), использование индекса является самым быстрым и надежным методом. Индекс — это порядковый номер значения в списке (начиная с 0), который является обычным числом.

Разберем алгоритм действий:

  1. В текущей базе получаем индекс значения перечисления.
  2. Передаем это число через COM-соединение.
  3. В подключаемой базе получаем значение по этому индексу.

// В текущей базе
ИндексЗначения = Перечисления.ЕдИзм.Индекс(Выборка.ЕдИзм);

// В подключаемой базе (через COM)
ОбъектБазы.ЕдИзм = База.Перечисления.ЕдИзм.Получить(ИндексЗначения);

Этот метод исключает проблемы с локализацией и различиями в синонимах, однако он требует строгого соответствия конфигураций. Если в одной базе добавить значение в середину списка перечисления, индексы «съедут», и данные синхронизируются неверно.

Способ 3. Использование функции ПредопределенноеЗначение

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

Проанализируем пример кода:


// Формируем путь в виде строки: "Перечисление.ИмяПеречисления.ИмяЗначения"
ПутьКЗначению = "Перечисление.ЕдИзм." + ИмяЗначения; 
ОбъектБазы.ЕдИзм = База.ПредопределенноеЗначение(ПутьКЗначению);

Для автоматизации получения полного имени можно воспользоваться встроенной функцией (если база-приемник позволяет такие вызовы):


ПолноеИмя = ПолучитьПолноеИмяПредопределенногоЗначения(Выборка.ЕдИзм);
ОбъектБазы.ЕдИзм = База.ПредопределенноеЗначение(ПолноеИмя);

Способ 4. Универсальная сериализация через XML

Если вы хотите написать максимально универсальный код, который не зависит от конкретного типа перечисления, стоит использовать механизмы XML-сериализации. Платформа умеет превращать любую ссылку в строку формата XML и обратно.

Выполним следующие шаги:

1. В исходной базе превращаем значение в XML-строку:


СтрокаXML = XMLСтрока(Выборка.ЕдИзм); // Вернет что-то вроде "Штука" или "Активен"

2. В подключаемой базе используем метод FromXMLString. Однако для этого метода нужно знать тип. Тип перечисления в XML-представлении выглядит как EnumRef.ИмяПеречисления.


ТипДляXML = "EnumRef." + Выборка.ЕдИзм.Метаданные().Имя;
ОбъектБазы.ЕдИзм = База.FromXMLString(ТипДляXML, СтрокаXML);

Этот метод считается одним из самых «чистых» с точки зрения архитектуры 1С, так как он использует внутренние механизмы платформы для работы с типами данных.

Оптимизация производительности при работе с COM

Выясним важную деталь: каждое обращение к свойствам через точку в COM-объекте (например, База.Перечисления.ЕдИзм.Получить(0)) — это отдельный вызов между процессами. Если вы обрабатываете тысячи строк в цикле, такие вызовы существенно замедлят работу.

Как оптимизировать процесс:

Обработка пустых значений

Никогда не забывайте про проверку на пустую ссылку. Если реквизит в исходной базе не заполнен, попытка получить его индекс приведет к ошибке выполнения. Проанализируем правильный подход:


Если Выборка.ЕдИзм.Пустая() Тогда
    ОбъектБазы.ЕдИзм = База.Перечисления.ЕдИзм.ПустаяСсылка();
Иначе
    // Используем один из методов выше
    Индекс = Перечисления.ЕдИзм.Индекс(Выборка.ЕдИзм);
    ОбъектБазы.ЕдИзм = База.Перечисления.ЕдИзм.Получить(Индекс);
КонецЕсли;

Подводя итог, можно сказать, что выбор метода зависит от ваших задач. Если базы идентичны — используйте индексы. Если базы разные или могут меняться — используйте поиск по имени или XML-сериализацию. Главное — всегда помнить, что через COM мы передаем информацию о значении, а не само значение.

← На главную