Как разбить один документ на несколько по количеству строк в табличной части в КД 2?

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

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

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

Причина создания только одного документа: механизм кэширования КД 2

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

Чтобы КД 2 воспринимала каждую порцию данных как отдельный независимый документ, необходимо явно передавать параметр КлючВыгружаемыхДанных.

Способ 1. Разбиение в ПВД через произвольный алгоритм (рекомендуемый)

Рассмотрим по шагам, как настроить правило выгрузки данных (ПВД) с типом «Произвольный алгоритм».

  1. Создаем ПВД с режимом выборки Произвольный алгоритм.
  2. В ПКО документа-приемника включаем флаг Получать данные из входящих данных.
  3. В обработчике ПВД «Перед обработкой» пишем алгоритм выборки и порционной выгрузки:

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Остатки.Номенклатура КАК Номенклатура,
    |    Остатки.Количество КАК Количество,
    |    Остатки.Сумма КАК Сумма
    |ИЗ
    |    РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК Остатки";
Запрос.УстановитьПараметр("Период", Параметры.ДатаОстатков);

Выборка = Запрос.Выполнить().Выгрузить();

ЛимитСтрок = 300;
НомерПачки = 1;
ТекущаяТЧ = Новый ТаблицаЗначений;
ТекущаяТЧ.Колонки.Добавить("Номенклатура");
ТекущаяТЧ.Колонки.Добавить("Количество");
ТекущаяТЧ.Колонки.Добавить("Сумма");

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

// Выгружаем остаток строк, не вошедших в полные пачки
Если ТекущаяТЧ.Количество() > 0 Тогда
    ИсходящиеДанные = Новый Структура;
    ИсходящиеДанные.Вставить("Дата", Параметры.ДатаОстатков);
    ИсходящиеДанные.Вставить("Организация", Параметры.Организация);
    ИсходящиеДанные.Вставить("Склад", Параметры.Склад);
    ИсходящиеДанные.Вставить("Комментарий", "Ввод остатков ч. " + Строка(НомерПачки));
    ИсходящиеДанные.Вставить("Товары", ТекущаяТЧ);
    
    КлючВыгрузки = "Остатки_Пачка_" + Строка(НомерПачки);
    
    ВыгрузитьПоПравилу(Неопределено, , ИсходящиеДанные, , "ВводОстатковТоваров", , , , КлючВыгрузки);
КонецЕсли;

Настройка поиска документов в базе-приемнике

После корректной выгрузки пачек в XML важно гарантировать, что при загрузке каждая пачка запишется как новый отдельный документ, а не перезапишет предыдущий. Разберем нюансы настройки полей поиска:

  1. Использование комментария или суффикса номера: Если перенос выполняется регулярно или возможна повторная синхронизация, включите реквизит Комментарий или сформированный уникальный номер в поля поиска ПКО. Тогда при повторной загрузке каждая пачка найдет строго свой документ.
  2. Принудительное создание новых объектов: Если выгрузка разовая, в обработчике ПКО «Поля поиска» можно прописать явный отказ от поиска:

ПрекратитьПоиск = Истина;

Это заставит механизм загрузки создавать новый документ для каждой порции данных из файла обмена.

Способ 2. Разбиение в обработчике «После загрузки» (на стороне приемника)

Если нет возможности модифицировать правила выгрузки источника, можно выгрузить большой документ целиком, а разделение на порции выполнить уже на стороне приемника в обработчике ПКО «После загрузки».

Проанализируем алгоритм:

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

Рекомендации по оптимизации и стабильности

  1. Очистка памяти: Обязательно вызывайте ТекущаяТЧ.Очистить() внутри цикла выгрузки. Накопление больших коллекций в оперативной памяти может привести к аварийному завершению процесса выгрузки.
  2. Режим записи при загрузке: Не проводите документы сразу при загрузке. Запись десятков новых документов с одновременным проведением в рамках единой транзакции обмена часто приводит к взаимоблокировкам (deadlock). Рекомендуется загружать документы не проведенными (в режиме РежимЗаписиДокумента.Запись), после чего запускать групповое проведение отдельной регламентной процедурой.
← На главную