Как получить ссылку для нового объекта в «Конвертации данных 2.1» до его записи в базу

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

При разработке правил обмена в Конвертации данных 2.1 (КД 2.1) программисты часто сталкиваются с задачей: при загрузке справочника нужно сразу создать запись в связанном регистре сведений (например, для хранения внешних кодов синхронизации). Основная сложность заключается в том, что в обработчике После загрузки новый объект еще не записан в базу данных, и его стандартное свойство Объект.Ссылка остается пустым. Если попытаться передать такую пустую ссылку в регистр, система выдаст ошибку.

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

Разбор проблемы: почему Ссылка пустая?

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

Рассмотрим ситуацию, описанную автором: при попытке вызвать Объект.УстановитьСсылкуНового() без параметров ничего не происходит, а попытка записи в регистр проваливается, так как поле Ссылка (ведущее измерение или реквизит регистра) не может быть пустым.

Решение №1: Использование методов ПолучитьСсылкуНового и УстановитьСсылкуНового

Это самый быстрый и правильный с точки зрения платформы 1С способ. Мы можем самостоятельно сгенерировать ссылку (GUID) и «сообщить» объекту, что при записи он должен использовать именно этот идентификатор. Разберем алгоритм действий в обработчике ПКО После загрузки:

1. Сначала проверим, является ли объект новым. Для этого в КД 2.1 есть встроенная переменная ОбъектНайден.

2. Если объект новый, попытаемся получить уже зарезервированную ссылку.

3. Если ссылка еще не была зарезервирована платформой, создадим её программно.

Посмотрим на пример «правильного кода»:


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

// Теперь переменную СсылкаДляРегистра можно смело использовать для записи в регистр
// Например, через создание набора записей или вызов алгоритма

Этот метод позволяет нам работать с объектом так, будто он уже существует, сохраняя при этом целостность транзакции обмена.

Почему метод «Просто вызвать Объект.Записать()» — плохой совет?

В обсуждениях часто встречается мнение: «Просто напишите Объект.Записать() в начале обработчика, и ссылка появится». Проанализируем, почему этого делать категорически не рекомендуется:

  1. Нарушение транзакционности: Правила конвертации обычно работают в рамках одной большой транзакции. Принудительная запись объекта может вызвать конфликты блокировок или привести к ситуации, когда объект записан, а связанные данные (которые могут вызвать ошибку позже) — нет.
  2. Лишняя нагрузка: Вызов Записать() провоцирует выполнение всех подписок на события «При записи», «Перед записью», выполнение движений и проверку прав. Сразу после завершения обработчика После загрузки, сама обработка конвертации все равно вызовет запись объекта еще раз. Таким образом, работа сервера удваивается.
  3. Дублирование логики: Если в конфигурации-приемнике стоят проверки на заполнение реквизитов, ручная запись может выдать ошибку раньше, чем КД 2.1 завершит инициализацию всех параметров объекта.

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

Решение №2: Использование функции ВыгрузитьПоПравилу

Если нам нужно не просто записать одну строчку в регистр, а выполнить полноценную конвертацию связанных данных, лучше воспользоваться архитектурным подходом КД 2.1. Вместо написания кода записи в регистр вручную (через СоздатьНаборЗаписей), мы можем создать отдельное ПКО (Правило конвертации объекта) для регистра сведений.

В этом случае в обработчике После загрузки справочника мы вызываем программную выгрузку:


// Подготовим структуру с данными для регистра
ПараметрыРегистра = Новый Структура;
ПараметрыРегистра.Вставить("Номенклатура", СсылкаДляРегистра);
ПараметрыРегистра.Вставить("ВнешнийКод", Объект.ВнешнийКод);

// Вызываем выгрузку по правилу для регистра
// "СинхронизацияВнешнихКодов" - это имя вашего ПКО для регистра
ВыгрузитьПоПравилу(,, ПараметрыРегистра,, "СинхронизацияВнешнихКодов");

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

Нюансы работы с GUID источника

Выясним еще одну деталь: иногда лучшим решением будет использование уникального идентификатора непосредственно из файла-источника. В КД 2.1 идентификатор источника доступен в обработчиках. Если мы принудительно установим ссылку нового объекта равной идентификатору из источника, мы обеспечим полную идентичность данных в обеих базах. Это избавляет от необходимости хранить «карты соответствия» в регистрах, так как поиск всегда будет идти по UID.

Для реализации этого подхода в ПКО Перед загрузкой или После загрузки (если объект новый) можно выполнить:


Если Не ОбъектНайден Тогда
    UID = Новый УникальныйИдентификатор(СокрЛП(ПараметрыОбъекта.Получить("ИдентификаторИсточника")));
    НоваяСсылка = Справочники.Номенклатура.ПолучитьСсылку(UID);
    Объект.УстановитьСсылкуНового(НоваяСсылка);
КонецЕсли;

Подведение итогов

Рассмотрев проблему получения ссылки нового объекта, мы пришли к следующим выводам:

Соблюдение этих правил гарантирует стабильную работу обмена данными, отсутствие «битых» ссылок в регистрах и высокую производительность системы при загрузке больших массивов информации.

← На главную