При организации обмена данными между базами 1С через COM-соединение разработчики часто сталкиваются с задачей переноса ссылочных объектов с сохранением их исходных уникальных идентификаторов (GUID). Попытка напрямую передать значение типа УникальныйИдентификатор из базы-источника в метод менеджера справочника базы-приемника приводит к исключению:
«Произошла исключительная ситуация: Несоответствие типов (параметр номер '1')».
Разберем детально, почему возникает данная ошибка, как правильно передавать идентификаторы через границу COM-процессов и как корректно создавать элементы с предопределенной ссылкой.
Проанализируем механизм передачи объектов через COM-соединение. Любой объект сложного платформенного типа (включая УникальныйИдентификатор, СправочникСсылка и другие), созданный в контексте базы-источника, передается через границу процессов в виде внешней COM-обертки (IDispatch).
Когда мы вызываем метод Соединение.Справочники.ФизическиеЛица.ПолучитьСсылку(...), контекст базы-получателя ожидает собственный внутренний объект типа УникальныйИдентификатор. Менеджер справочника не может неявно преобразовать чужой COM-объект источника к своему внутреннему типу данных, что и вызывает ошибку типизации.
Кроме того, распространенной ошибкой является попытка передать полученную ссылку в качестве параметра методов СоздатьЭлемент() или СоздатьГруппу(). Согласно синтаксису платформы 1С:Предприятие, эти методы не принимают параметров. Назначение конкретной ссылки выполняется отдельно через специализированный метод объекта УстановитьСсылкуНового().
Рассмотрим правильный и надежный порядок действий по переносу ссылки через COM-соединение.
Строка() или XMLСтрока(). Строковые примитивы без искажений передаются через COM.УникальныйИдентификатор в контексте базы-получателя через вызов Соединение.NewObject().ПолучитьСсылку().УстановитьСсылкуНового() до момента его записи.Посмотрим на готовый фрагмент кода, реализующий перенос физического лица из базы-источника в базу-приемник с полным сохранением уникального идентификатора:
// 1. Получаем ссылку и ее строковый GUID в базе-источнике
СсылкаИсточник = Справочники.ФизическиеЛица.НайтиПоНаименованию("Иванов Иван Иванович");
Если Не ЗначениеЗаполнено(СсылкаИсточник) Тогда
ВызватьИсключение "Объект в источнике не найден!";
КонецЕсли;
СтрокаУИД = Строка(СсылкаИсточник.УникальныйИдентификатор());
// 2. В контексте базы-приемника инициализируем новый УникальныйИдентификатор
УИДПолучатель = Соединение.NewObject("УникальныйИдентификатор", СтрокаУИД);
// 3. Получаем ссылку в базе-получателе
СсылкаПолучатель = Соединение.Справочники.ФизическиеЛица.ПолучитьСсылку(УИДПолучатель);
// 4. Проверяем, существует ли уже объект с такой ссылкой в базе-приемнике
ОбъектПолучатель = СсылкаПолучатель.ПолучитьОбъект();
Если ОбъектПолучатель = Неопределено Тогда
// Объекта нет — создаем новый и привязываем ссылку
ОбъектПолучатель = Соединение.Справочники.ФизическиеЛица.СоздатьЭлемент();
ОбъектПолучатель.УстановитьСсылкуНового(СсылкаПолучатель);
КонецЕсли;
// 5. Заполняем реквизиты и записываем объект
ОбъектПолучатель.Наименование = СсылкаИсточник.Наименование;
// Заполнение остальных реквизитов...
ОбъектПолучатель.Записать();
Разберем ключевые особенности платформы, которые необходимо учитывать при генерации ссылок:
ПолучитьСсылку() не создает запись в базе данных: он лишь формирует ссылку заданного типа на основе переданного идентификатора. Проверить фактическое наличие элемента в базе можно вызовом Ссылка.ПолучитьОбъект().УстановитьСсылкуНового() можно вызывать исключительно для объектов, у которых свойство ЭтоНовый() возвращает Истина. После первой записи объекта вызов этого метода вызовет исключение.УникальныйИдентификатор, попытка записи нового объекта с дублирующейся ссылкой приведет к ошибке на уровне СУБД из-за нарушения первичного ключа таблицы. Всегда выполняйте проверку на существование объекта перед созданием нового.Если требуется переносить большой массив справочников или документов, пообъектная работа через COM может работать медленно из-за сетевых накладных расходов на каждый вызов. Рассмотрим более производительные альтернативы:
СериализаторXDTO.ЗаписатьXML(), а в базе-получателе считывается через Соединение.СериализаторXDTO.ПрочитатьXML(). Этот механизм автоматически сохраняет оригинальные идентификаторы и состав реквизитов.