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

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

При интеграции двух информационных баз 1С с помощью внешнего соединения часто возникает задача синхронизации справочников с сохранением исходных идентификаторов. При попытке передать ссылку на объект или уникальный идентификатор напрямую через границу COM-соединения разработчики сталкиваются с исключением: Ошибка при вызове конструктора (УникальныйИдентификатор): Недопустимое значение параметра (параметр номер '1'). Разберем детально, почему возникает данная ошибка и как правильно реализовать передачу идентификаторов и создание элементов с заданным GUID.

Анализ проблемы и механизма работы COM-объектов

Рассмотрим типовую ситуацию. Из базы-источника вызывается экспортная функция общего модуля базы-приемника, куда в качестве параметра передается ссылка на объект:


// Вызов в базе-источнике
Ответ = БазаШК.СоздатьНоменклатуру(СсылкаНоменклатура);

В модуле базы-приемника код пытается извлечь УникальныйИдентификатор и получить по нему ссылку для нового элемента:


Функция СоздатьНоменклатуру(Номенклатура) Экспорт
    ГУИД = Номенклатура.УникальныйИдентификатор;
    РезСсылка = Справочники._Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Строка(ГУИД)));
    // ... дальнейшие действия
КонецФункции

На строке инициализации конструктора Новый УникальныйИдентификатор(...) выполнение прерывается с ошибкой. Выясним причину такого поведения платформы 1С:

  1. Неявное создание COM-прокси: При передаче сложных типов (таких как СправочникСсылка или УникальныйИдентификатор) через COM-соединение база-приемник получает не нативный объект 1С, а специальную интерфейсную обертку типа COMОбъект.
  2. Особенности функции преобразования: Функция Строка(), примененная к COMОбъекту в удаленной базе, не преобразует значение в нативную строку формата GUID, а возвращает ссылку на COM-объект или его внутреннее системное описание.
  3. Строгая типизация конструктора: Конструктор Новый УникальныйИдентификатор(Параметр) ожидает на вход исключительно строку стандартного формата (36 символов с дефисами). Передача объекта типа COMОбъект приводит к ошибке типизации.
  4. Накладные расходы (RPC): Обращение к свойствам полученного COM-объекта (например, Номенклатура.Код, Номенклатура.Наименование) порождает множество межпроцессных сетевых вызовов, что существенно замедляет пакетную обработку данных.

Способ 1. Передача строкового GUID и примитивных типов (Основное решение)

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

Разберем по шагам правильную организацию обмена.

Шаг 1. Формирование данных в базе-источнике:


Для Каждого СтрокаТЧ Из ТаблицаНоменклатуры Цикл
    ПараметрыЭлемента = Новый Структура;
    ПараметрыЭлемента.Вставить("ГУИД", Строка(СтрокаТЧ.Номенклатура.УникальныйИдентификатор()));
    ПараметрыЭлемента.Вставить("Код", СтрокаТЧ.Номенклатура.Код);
    ПараметрыЭлемента.Вставить("Наименование", СтрокаТЧ.Номенклатура.Наименование);
    
    // Передаем структуру с примитивными данными
    Результат = БазаПриемник.СоздатьНоменклатуру(ПараметрыЭлемента);
КонецЦикла;

Шаг 2. Прием данных и создание элемента с фиксированным GUID в базе-приемнике:


Функция СоздатьНоменклатуру(ПараметрыЭлемента) Экспорт
    
    СтрокаГУИД = СокрЛП(ПараметрыЭлемента.ГУИД);
    Идентификатор = Новый УникальныйИдентификатор(СтрокаГУИД);
    
    // Получаем ссылку по переданному GUID
    ЦелеваяСсылка = Справочники.Номенклатура.ПолучитьСсылку(Идентификатор);
    
    // Проверяем существование объекта в базе
    ОбъектНоменклатура = ЦелеваяСсылка.ПолучитьОбъект();
    
    Если ОбъектНоменклатура = Неопределено Тогда
        // Создаем новый объект и фиксируем за ним ссылку ДО первой записи
        ОбъектНоменклатура = Справочники.Номенклатура.СоздатьЭлемент();
        ОбъектНоменклатура.УстановитьСсылкуНового(ЦелеваяСсылка);
    КонецЕсли;
    
    ОбъектНоменклатура.Код = ПараметрыЭлемента.Код;
    ОбъектНоменклатура.Наименование = ПараметрыЭлемента.Наименование;
    
    Попытка
        ОбъектНоменклатура.Записать();
        Возврат Истина;
    Исключение
        ЗаписьЖурналаРегистрации("Синхронизация COM", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        Возврат Ложь;
    КонецПопытки;
    
КонецФункции

Способ 2. Использование механизмов платформенной XML-сериализации

Если требуется гарантировать полную корректность формата идентификатора при передаче между базами 1С, рекомендуется использовать встроенные функции платформы для работы с XML-строками: XMLСтрока() и XMLЗначение().

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

В базе-источнике формируем строковое представление ссылки:


// XMLСтрока сразу возвращает чистый строковый GUID
СтрокаGUID = XMLСтрока(СсылкаНоменклатура);
Ответ = БазаПриемник.СоздатьНоменклатуруПоXML(СтрокаGUID, СсылкаНоменклатура.Наименование, СсылкаНоменклатура.Код);

В базе-приемнике восстанавливаем ссылку напрямую через XMLЗначение:


Функция СоздатьНоменклатуруПоXML(СтрокаGUID, Наименование, Код) Экспорт
    
    // Получаем типизированную ссылку напрямую из XML-строки
    ЦелеваяСсылка = XMLЗначение(Тип("СправочникСсылка.Номенклатура"), СтрокаGUID);
    
    ОбъектНоменклатура = ЦелеваяСсылка.ПолучитьОбъект();
    Если ОбъектНоменклатура = Неопределено Тогда
        ОбъектНоменклатура = Справочники.Номенклатура.СоздатьЭлемент();
        ОбъектНоменклатура.УстановитьСсылкуНового(ЦелеваяСсылка);
    КонецЕсли;
    
    ОбъектНоменклатура.Наименование = Наименование;
    ОбъектНоменклатура.Код = Код;
    ОбъектНоменклатура.Записать();
    
    Возврат ЦелеваяСсылка;
    
КонецФункции

Важные правила использования метода УстановитьСсылкуНового

Проанализируем технические нюансы работы метода УстановитьСсылкуНового(), нарушение которых приводит к труднодиагностируемым ошибкам:

  1. Момент вызова метода: Метод УстановитьСсылкуНового() можно вызывать только для нового, еще не записанного в базу объекта (созданного через СоздатьЭлемент()) и строго до первого вызова метода Записать().
  2. Отсутствие немедленной валидации: Метод не выполняет проверку базы на наличие дубликатов в момент назначения ссылки. Если в таблице уже существует элемент с таким GUID, ошибка контроля уникальности первичного ключа возникнет только при выполнении метода Записать().
  3. Оптимизация проверки существования: Если база содержит большой объем данных или сложные реквизиты, вызов ЦелеваяСсылка.ПолучитьОбъект() выполняет полное считывание всех табличных частей. Для высоконагруженных обменов проверку наличия ссылки лучше выполнять легковесным запросом к таблице справочника:
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |   Спр.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.Номенклатура КАК Спр
        |ГДЕ
        |   Спр.Ссылка = &Ссылка";
    Запрос.УстановитьПараметр("Ссылка", ЦелеваяСсылка);
    Результат = Запрос.Выполнить();
    Существует = НЕ Результат.Пустой();
    
← На главную