При настройке правил обмена в конфигурации «Конвертация данных 2.1» (КД 2.1), используя в процессе разработки портативный обозреватель правил конвертации, часто возникает задача выполнить дополнительные действия с объектами не в момент их записи, а после того, как все данные уже загружены. Например, нам необходимо сформировать движения по независимым регистрам сведений, запустить сложные алгоритмы расчетов или заполнить таблицы связей, используя ссылки на только что созданные документы или справочники.
Основная сложность здесь заключается в том, чтобы корректно собрать коллекцию ссылок на этапе загрузки, особенно когда выполняется адаптивная выгрузка и загрузка данных XML между не полностью идентичными конфигурациями и речь идет о создании новых объектов, которые физически еще не записаны в базу данных в момент выполнения обработчиков ПКО (Правил конвертации объектов). В этой статье мы подробно разберем, как реализовать механизм отложенной обработки, правильно инициализировать параметры и использовать метод ПолучитьСсылкуНового().
Предположим, наша цель — собрать массив ссылок на определенные документы в процессе загрузки, а затем, в самом конце сеанса обмена, пройтись по этому массиву и выполнить запись в регистры. Подобная логика часто закладывается в сложные правила обмена между КА 2.5 и WMS 5, где требуется высокая точность сопоставления данных.
Для реализации этого сценария нам потребуются три ключевых этапа:
Разберем каждый этап детально.
Первая ошибка, которую часто совершают разработчики — попытка объявить переменную в неправильном месте. Чтобы наш массив был доступен на протяжении всего сеанса загрузки (и в ПКО, и в глобальных обработчиках), необходимо использовать коллекцию «Параметры».
Инициализировать эту коллекцию правильнее всего в глобальном обработчике Перед загрузкой данных. Этот обработчик выполняется один раз перед началом чтения файла данных.
Напишем код инициализации:
// Глобальный обработчик: Перед загрузкой данных
// Инициализируем массив, куда будем складывать ссылки
Параметры.Вставить("СписокДокументовДляОбработки", Новый Массив);
Теперь у нас есть глобально доступный массив Параметры.СписокДокументовДляОбработки, к которому мы можем обращаться из любого правила конвертации.
Теперь перейдем к правилам конвертации объектов (ПКО), для которых нам нужно собрать ссылки. Подходящим местом для перехвата объекта является обработчик После загрузки.
Здесь кроется важный нюанс. В этот момент объект уже сформирован в памяти (заполнены его реквизиты из файла), но он еще не записан в базу данных.
Ссылка.Ссылка у него может еще не быть (или она не определена, так как запись не произошла), но платформе уже известен уникальный идентификатор (GUID), под которым этот объект "ляжет" в базу.Чтобы универсально получить ссылку и для новых, и для существующих объектов, нам поможет использование метода ПолучитьСсылкуНового(). Рассмотрим правильный алгоритм:
// ПКО: Ваш_Документ -> Обработчик: После загрузки
// Проверяем, новый это объект или найденный
Если Объект.ЭтоНовый() Тогда
// Для новых объектов получаем ссылку, которая будет присвоена при записи
СсылкаНаОбъект = Объект.ПолучитьСсылкуНового();
Иначе
// Для найденных объектов берем уже существующую ссылку
СсылкаНаОбъект = Объект.Ссылка;
КонецЕсли;
// Добавляем полученную ссылку в наш глобальный параметр
Параметры.СписокДокументовДляОбработки.Добавить(СсылкаНаОбъект);
Важно: Использование ПолучитьСсылкуНового() критично. Если вы попытаетесь обратиться к Объект.Ссылка у ненаписанного нового элемента, вы можете получить пустую ссылку, и ваша дальнейшая логика не сработает.
Когда обмен завершен, все объекты прочитаны и записаны в базу данных, система вызывает глобальный обработчик После загрузки данных. В этот момент мы можем быть уверены, что все ссылки, которые мы собрали в массив, уже являются валидными ссылками на существующие в БД объекты.
Реализуем логику обхода массива для постобработки записей в независимых регистрах сведений:
// Глобальный обработчик: После загрузки данных
// Проверяем, есть ли что обрабатывать
Если Параметры.СписокДокументовДляОбработки.Количество() > 0 Тогда
// Включаем режим загрузки, чтобы при записи движений не срабатывали лишние проверки
ОбменДанными.Загрузка = Истина;
Для Каждого ДокСсылка Из Параметры.СписокДокументовДляОбработки Цикл
// Пример: Запись в независимый регистр сведений
НаборЗаписей = РегистрыСведений.НашРегистр.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ДокументОснование.Установить(ДокСсылка);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ДокументОснование = ДокСсылка;
НоваяЗапись.Значение = "Обработано при обмене";
Попытка
НаборЗаписей.Записать();
Исключение
Сообщить("Ошибка при пост-обработке документа " + Строка(ДокСсылка) + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецЕсли;
При реализации данного подхода необходимо учитывать несколько моментов, чтобы не нарушить работу базы данных и производительность обмена.
1. Отказы при записи
В обработчике ПКО «После загрузки» мы добавляем ссылку в массив. Однако, после выполнения этого обработчика система попытается записать объект. Если запись не удастся, то в вашем массиве останется «битая» ссылка. Перед использованием накопленных данных рекомендуется проверять существование объектов в базе.
2. Объем данных и память
Использование массива в параметрах идеально подходит для небольших объемов. Однако при очень больших обменах хранение сотен тысяч ссылок в памяти может вызвать её переполнение. Для повышения стабильности в таких случаях можно использовать передачу объектов по одному через RabbitMQ в связке с КД 2.
В случае сверхбольших объемов рекомендуется использовать другую архитектуру: вместо добавления в массив записывать ссылки во временный регистр сведений, а затем обрабатывать эту очередь фоновым заданием. В некоторых проектах, когда типовых возможностей обмена становится недостаточно, отличным решением будет комфортная работа с Универсальным обменом XML и RabbitMQ.
3. Транзакции
Глобальный обработчик «После загрузки данных» часто выполняется в рамках транзакции обмена. Реализация сложных алгоритмов в этот момент может привести к длительным блокировкам таблиц. Если логика позволяет, старайтесь минимизировать тяжелые операции внутри транзакции загрузки.
Для успешной постобработки объектов в КД 2.1:
Параметры в обработчике Перед загрузкой данных.Если Объект.ЭтоНовый() Тогда ... Объект.ПолучитьСсылкуНового().Если же ваша задача выходит за рамки стандартного обмена через файлы, вы можете рассмотреть универсальный перенос данных между конфигурациями через COM или HTTP, который предоставляет еще больше гибкости при работе с объектами в реальном времени.