Почему не присваивается УникальныйИдентификатор при синхронизации через COMConnector?

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

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

Суть проблемы и анализ исходного кода

Типичный алгоритм переноса объекта через COM-соединение выглядит следующим образом: мы создаем объект в целевой базе, генерируем ссылку на основании GUID из исходной базы и пытаемся установить эту ссылку новому объекту. Разберем пример кода, который часто используется для этих целей:


Если НовыйДок Тогда
    // Создаем ссылку в целевой базе на основании GUID из исходной базы
    НоваяСсылка = БазаК.Документы[ЗначениеК].ПолучитьСсылку(БазаК.NewObject("УникальныйИдентификатор", Строка(Док.УникальныйИдентификатор())));
    
    // Пытаемся назначить эту ссылку новому (еще не записанному) объекту
    ОбъектК.SetNewObjectRef(НоваяСсылка);
КонецЕсли;

// Записываем объект
ОбъектК.Записать(?(Проводить, БазаК.РежимЗаписиДокумента.Проведение, БазаК.РежимЗаписиДокумента.Запись));

Проблема заключается в том, что в некоторых типах документов (в нашем случае это ПКО) после вызова метода Записать() объект в базе данных получает совершенно другой идентификатор, игнорируя установленный через SetNewObjectRef(). Это происходит даже несмотря на то, что для других видов документов этот же код работает безупречно.

Разбор причины: Внутренняя логика конфигурации

Выясним причину такого поведения. В типовых конфигурациях 1С (УПП, КА, ERP) модули объектов содержат множество обработчиков событий, таких как ПередЗаписью, ПриЗаписи, а также подписки на события. Для кассовых документов (ПКО, РКО) предусмотрена особо строгая логика контроля.

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

Решение проблемы: Использование свойства ОбменДанными.Загрузка

Для решения подобных проблем в платформе 1С предусмотрен специальный механизм. Чтобы «сообщить» объекту, что он не создается пользователем, а загружается из внешней системы, необходимо установить свойство ОбменДанными.Загрузка в значение Истина.

Посмотрим на исправленный алгоритм:


Если НовыйДок Тогда
    НоваяСсылка = БазаК.Документы[ЗначениеК].ПолучитьСсылку(БазаК.NewObject("УникальныйИдентификатор", Строка(Док.УникальныйИдентификатор())));
    ОбъектК.SetNewObjectRef(НоваяСсылка);
КонецЕсли;

// Ключевая строка для решения проблемы
ОбъектК.ОбменДанными.Загрузка = Истина; 

ОбъектК.Записать(?(Проводить, БазаК.РежимЗаписиДокумента.Проведение, БазаК.РежимЗаписиДокумента.Запись));

Что происходит при установке этого флага?

  1. Отключение прикладных проверок: Платформа и конфигурация понимают, что данные поступают извне. Большинство проверок в процедуре ПередЗаписью (например, проверка заполнения реквизитов или корректность GUID) будут пропущены.
  2. Игнорирование подписок: Многие системные подписки на события, которые могут изменять объект «на лету», прекращают свою работу для данного сеанса записи.
  3. Сохранение идентификатора: Платформа перестает пытаться переопределить ссылку, установленную через SetNewObjectRef(), и записывает объект именно с тем GUID, который был передан.

Важные технические нюансы работы с COM

Рассмотрим еще несколько критически важных моментов, которые могут влиять на результат при работе через COMConnector:

1. Контекст создания идентификатора. Обратите внимание, что в коде УникальныйИдентификатор создается именно в контексте целевой базы: БазаК.NewObject("УникальныйИдентификатор", ...). Это обязательное условие. Если попытаться передать объект идентификатора, созданный в текущей базе, COM-соединение может неверно интерпретировать типы данных, что приведет к ошибке или игнорированию значения.

2. Состояние объекта. Метод SetNewObjectRef() (или УстановитьСсылкуНового()) работает исключительно для объектов, которые еще ни разу не были записаны в базу данных. Если в вашем коде где-то выше по стеку вызовов случайно затесалась промежуточная запись объекта, установить ему новый GUID уже не получится.

3. Влияние СУБД (PostgreSQL). Хотя база данных на PostgreSQL накладывает свои особенности на хранение индексов, на логическом уровне 1С GUID остается 16-байтовым бинарным полем. Если после установки ОбменДанными.Загрузка = Истина проблема сохраняется, стоит проверить, нет ли в базе «битых ссылок» или объектов с таким же GUID, помеченных на удаление. В PostgreSQL в редких случаях (особенно на старых версиях платформы, таких как 8.3.15) кэширование индексов может приводить к конфликтам при попытке записи объекта с уже существующим в индексе идентификатором.

Альтернативный взгляд: REST API vs COM

Разберем ситуацию в контексте современных подходов. Использование COMConnector (технология OLE/COM) постепенно уходит в прошлое. Начиная с версии 8.3.15, разработчики все чаще смотрят в сторону REST интерфейса (OData) или HTTP-сервисов.

Преимущества альтернативных методов:

Тем не менее, если ваша текущая задача ограничена рамками уже написанного COM-обмена, установка ОбменДанными.Загрузка = Истина является самым быстрым и эффективным решением, которое гарантирует сохранение уникальных идентификаторов при миграции данных.

← На главную