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