Как в КД 2 настроить запрет замещения объектов, если они выгружаются по ссылкам, а не по правилам выгрузки?

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

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

Разберем, почему стандартные подходы с созданием двух отдельных ПКО вызывают сложности, выясним причину такого поведения движка конвертации и рассмотрим надежные программные способы реализации этой логики.

Почему создание двух ПКО не всегда решает проблему

Интуитивное решение задачи — создать два правила конвертации объектов (ПКО):

  1. Основное ПКО — используется в ПВД, где включена штатная перезапись объектов в приемнике.
  2. Вспомогательное ПКО — настраивается специально для ссылок, в нем снимается флаг Не замещать объект при загрузке (или устанавливается признак Не замещать существующие).

Однако при практической реализации разработчик неизбежно сталкивается со следующими ограничениями механизмов КД2:

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

Способ 1. Контроль глубины стека через глобальный счетчик в параметрах

Наиболее универсальный способ — использовать одно ПКО для объекта и динамически определять контекст его выгрузки. Попытка использовать простой булевый флаг вида Параметры.ВыгруженоИзПВД = Истина часто сбоит: корневой объект тянет за собой подчиненные ссылки, и флаг сбрасывается преждевременно или передается дочерним элементам.

Проанализируем надежный алгоритм со счетчиком глубины выгрузки. Он позволяет точно понимать, выгружается ли объект сам по себе (как корень из ПВД) или как зависимый реквизит.

Шаг 1. В обработчике конвертации Перед выгрузкой данных инициализируем переменную стека:

Параметры.Вставить("ГлубинаВыгрузки", 0);

Шаг 2. В глобальном обработчике конвертации Перед конвертацией объекта (или в обработчике ПКО Перед выгрузкой) инкрементируем счетчик и задаем режим замещения:


Параметры.ГлубинаВыгрузки = Параметры.ГлубинаВыгрузки + 1;

// Если глубина > 1, значит, выгрузка инициирована из другого объекта по ссылке
Если Параметры.ГлубинаВыгрузки > 1 Тогда
    НеЗамещатьОбъектПриЗагрузке = Истина;
Иначе
    НеЗамещатьОбъектПриЗагрузке = Ложь;
КонецЕсли;

Шаг 3. В глобальном обработчике После конвертации объекта (или в ПКО После выгрузки) обязательно уменьшаем значение счетчика:

Параметры.ГлубинаВыгрузки = Параметры.ГлубинаВыгрузки - 1;

Этот подход работает автоматически для любых справочников и типов без необходимости прописывать персональные условия в каждом ПКС.

Способ 2. Передача контекста через «ИсходящиеДанные» и «ВходящиеДанные»

Механизм передачи контекстных данных в КД2 устроен так, что данные из ПВД не проваливаются автоматически в подчиненные ссылки, если это не задано явно в ПКС. Мы можем использовать эту особенность:

Шаг 1. В ПВД в обработчике Перед обработкой или Перед выгрузкой инициализируем контекст выгрузки:

ИсходящиеДанные = Новый Структура("ПрямаяВыгрузкаИзПВД", Истина);

Шаг 2. В обработчике Перед выгрузкой соответствующего ПКО проверяем наличие структуры во входящих данных. Если объект выгружается по ссылке через ПКС, переменная ВходящиеДанные будет равна Неопределено:


Если ВходящиеДанные <> Неопределено 
   И ВходящиеДанные.Свойство("ПрямаяВыгрузкаИзПВД") 
   И ВходящиеДанные.ПрямаяВыгрузкаИзПВД = Истина Тогда
    НеЗамещатьОбъектПриЗагрузке = Ложь;
Иначе
    НеЗамещатьОбъектПриЗагрузке = Истина;
КонецЕсли;

Способ 3. Перенос логики на сторону загрузки (в базу-приемник)

Иногда логику безопаснее реализовать непосредственно в момент записи в приемнике. В этом случае на стороне источника мы передаем через параметры объекта признак того, как именно он был отправлен.

Шаг 1. В источнике в ПКО в событии Перед выгрузкой передаем признак в структуру ПараметрыОбъекта:


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

Шаг 2. В базе-приемнике в ПКО открываем обработчик При загрузке и управляем штатным параметром НеЗамещатьОбъект:


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

В такой схеме новый объект будет корректно создан и заполнен. Если же элемент уже существовал и поступил как зависимая ссылка, его реквизиты останутся нетронутыми, а ссылка корректно подставится в документ-родитель.

Способ 4. Динамическое назначение ПКО для составных типов

Если архитектура конвертации требует использования двух строго раздельных ПКО (например, для одного типа настроены сложные алгоритмы заполнения реквизитов, которые не нужны при выгрузке по ссылке), можно переопределять правило динамически.

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


Если ЗначениеЗаполнено(Значение) Тогда
    // Формируем наименование вспомогательного ПКО на основе метаданных значения
    ИмяПКО = "ПоСсылкам_" + Значение.Метаданные().Имя;
КонецЕсли;

Важный нюанс: порядок ПВД и очистка кэша ссылок

При любом выбранном способе необходимо учитывать поведение таблицы ВыгруженныеОбъекты:

  1. Порядок следования ПВД. Настройте порядок правил выгрузки в дереве так, чтобы нормативно-справочная информация (справочники) выгружалась раньше, чем документы и регистры. Тогда данные справочников сначала пройдут полную обработку по ПВД с обновлением реквизитов, и последующие ссылки из документов уже не повлияют на их состояние.
  2. Сброс запоминания объекта. Если объект выгружается через отдельное ПКО по ссылке, в обработчике Перед выгрузкой этого ПКО полезно указать флаг НеЗапоминатьВыгруженные = Истина;. Это исключит ситуацию, когда ссылка зарегистрируется в кэше и заблокирует дальнейшую полную выгрузку элемента из собственного ПВД.
← На главную