При разработке собственных механизмов синхронизации данных с использованием формата Enterprise Data и библиотек стандартных подсистем (БСП) разработчики нередко сталкиваются с проблемой обработки удаленных элементов. Если выгрузка обычных элементов справочников или документов проходит штатно, то при попытке отправить зарегистрированное изменение типа УдалениеОбъекта стандартный вызов метода ОбменДаннымиXDTOСервер.ВыгрузкаОбъектаВыборки завершается аварийно. Проанализируем, почему возникает эта ошибка, и разберем практические способы корректной выгрузки удалений в XML-пакет Enterprise Data.
Выясним причину сбоя при передаче типа УдалениеОбъекта в процедуру выгрузки. Штатный метод ОбменДаннымиXDTOСервер.ВыгрузкаОбъектаВыборки рассчитан на работу с реальными объектами информационной базы (например, СправочникОбъект, ДокументОбъект) либо их ссылками. Внутри тела этого метода система пытается сразу обратиться к свойствам метаданных через конструкцию Объект.Метаданные().
Однако системный тип УдалениеОбъекта устроен иначе: у него нет прямого метода Метаданные() на верхнем уровне. Ссылка на удаленный элемент и соответствующий ей объект метаданных доступны только через вложенное свойство: ОбъектОбмена.Ссылка.Метаданные(). Из-за этого прямое использование процедуры приводит к исключительной ситуации.
Кроме того, в БСП механизмы выгрузки разделены на два параллельных потока:
ВыгрузкаОбъектаВыборки;ВыгрузитьУдаление.При этом вызов процедуры ВыгрузитьУдаление тоже может завершиться неудачей: удаление просто не попадает в итоговый XML-файл. Это происходит из-за внутренней проверки ОбъектФорматаПроходитПоФильтруXDTO, которая сверяет тип с коллекцией КомпонентыОбмена.ПоддерживаемыеОбъектыXDTO. Если обмен инициализирован без указания узла плана обмена или с параметром ЭтоОбменЧерезПланОбмена = Ложь, эта коллекция остается пустой, и алгоритм отсекает объект как неподдерживаемый корреспондентом.
Если обмен выполняется в нетиповом сценарии (например, через прямые вызовы без привязки к конкретному узлу плана обмена БСП), наиболее надежным решением будет самостоятельный поиск подходящих правил конвертации и запись узла удаления в поток данных. Разберем этот алгоритм.
В цикле обхода зарегистрированных изменений разделим обработку живых данных и удаленных ссылок. Для типа УдалениеОбъекта найдем правила обработки данных по метаданным ссылки, получим соответствующее ПКО и передадим данные в метод записи XDTO. Посмотрим на пример кода:
Если ТипЗнч(ОбъектОбмена) = Тип("УдалениеОбъекта") Тогда
СсылкаНаОбъект = ОбъектОбмена.Ссылка;
МетаданныеОбъекта = СсылкаНаОбъект.Метаданные();
// Ищем правило обработки данных для метаданных объекта
СтрокаПОД = КомпонентыОбмена.ПравилаОбработкиДанных.Найти(МетаданныеОбъекта, "ОбъектВыборкиМетаданные");
Если СтрокаПОД <> Неопределено Тогда
МассивИменПКО = СтрокаПОД.ИспользуемыеПКО;
Для Каждого ПравилоКонвертацииИмя Из МассивИменПКО Цикл
ПравилоКонвертации = КомпонентыОбмена.ПравилаКонвертацииОбъектов.Найти(ПравилоКонвертацииИмя, "ИмяПКО");
Если ПравилоКонвертации = Неопределено Тогда
// Пропускаем правила, не предназначенные для текущей версии формата
Продолжить;
КонецЕсли;
ТипСсылкиXDTO = ПравилоКонвертации.ТипСсылкиXDTO;
// Записываем секцию удаления объекта в XML-поток
ЗаписатьУдалениеОбъектаXDTO(КомпонентыОбмена, СсылкаНаОбъект, ТипСсылкиXDTO);
КонецЦикла;
КонецЕсли;
Иначе
// Обычная выгрузка существующего объекта
ОбменДаннымиXDTOСервер.ВыгрузкаОбъектаВыборки(КомпонентыОбмена, ОбъектОбмена);
КонецЕсли;
Рассмотрим, что здесь происходит: мы извлекаем реальную ссылку через ОбъектОбмена.Ссылка, по ее метаданным определяем перечень правил конвертации и передаем тип XDTO в процедуру ЗаписатьУдалениеОбъектаXDTO, минуя проверку массива поддерживаемых объектов корреспондента.
Если мы хотим использовать стандартные методы БСП без обхода внутренних структур вручную, необходимо правильно подготовить саму структуру КомпонентыОбмена перед началом выборки данных. Основная задача — заставить подсистему заполнить массив ПоддерживаемыеОбъектыXDTO.
Разберем по шагам, как настроить контекст обмена:
ОбменДаннымиXDTOСервер.ИнициализироватьКомпонентыОбмена убедимся, что установлены флаги:
КомпонентыОбмена.ЭтоОбменЧерезПланОбмена = Истина;
КомпонентыОбмена.УзелКорреспондента = УзелОбмена; // Ссылка на узел используемого плана обмена
ОбменДаннымиXDTOСервер.ЗаполнитьПоддерживаемыеОбъектыXDTO(КомпонентыОбмена);
КомпонентыОбмена.ПоддерживаемыеОбъектыXDTO можно заполнить программно именами типов формата XDTO, которые присутствуют в правилах конвертации.
Если ТипЗнч(ОбъектОбмена) = Тип("УдалениеОбъекта") Тогда
ОбменДаннымиXDTOСервер.ВыгрузитьУдаление(КомпонентыОбмена, ОбъектОбмена.Ссылка);
Иначе
ОбменДаннымиXDTOСервер.ВыгрузкаОбъектаВыборки(КомпонентыОбмена, ОбъектОбмена);
КонецЕсли;
Чтобы избежать ручного разделения потоков выгрузки и проверок на тип УдалениеОбъекта, можно воспользоваться готовыми высокоуровневыми процедурами БСП, которые берут на себя весь цикл работы с выборкой изменений:
ОбменДаннымиXDTOСервер.ВыполнитьВыгрузкуЗарегистрированныхДанных(КомпонентыОбмена, НомерСообщения);
Внутри этой процедуры подсистема самостоятельно считывает изменения из плана обмена, определяет тип каждой записи и автоматически направляет удаленные объекты в процедуру выгрузки удалений, а существующие элементы — в процедуру конвертации данных.
При проектировании обмена важно помнить о специфике формата Enterprise Data при обработке удалений:
УдалениеОбъекта на стороне базы-приемника не удаляет запись из базы данных физически. Типовые алгоритмы БСП находят объект по идентификатору и устанавливают свойство ПометкаУдаления = Истина (а для документов дополнительно отменяют проведение).