Как настроить перенос регистра сведений с разной структурой и периодичностью в КД 2.1?

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

При настройке правил обмена в конфигурации 1С:Конвертация данных 2.1 нередко возникают ситуации, когда структуры переносимых регистров сведений в базе-источнике (База А) и базе-приемнике (База Б) существенно отличаются. Рассмотрим типичный сценарий:

  1. В источнике регистр является периодическим, где Номенклатура — измерение, а Сегмент — ресурс.
  2. В приемнике аналогичный регистр непериодический, и в нем Номенклатура и Сегмент — оба являются измерениями.
  3. В источнике присутствует служебное значение Без сегмента. При его установке в базе-приемнике требуется полностью удалить все записи по данной номенклатуре, а при обычных сегментах — актуализировать запись, не создавая дублирующих строк.

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

Анализ возникающих проблем

Проанализируем две ключевые сложности типового механизма загрузки КД 2.1 при такой структуре данных:

  1. Различие в периодичности: прямая выгрузка записей из базы А выгрузит всю историю изменений регистра. Однако в непериодическом регистре базы Б история не хранится.
  2. Различие в составе измерений: так как в базе Б поле Сегмент выступает измерением, стандартная запись новой строки КД 2.1 не перезапишет старую запись с другим сегментом, а добавит вторую строку, сформировав несколько активных сегментов для одной позиции номенклатуры.
  3. Очистка при значении «Без сегмента»: стандартная загрузка создает или обновляет записи, но не умеет удалять старые наборы записей по условию.

Шаг 1. Выгрузка актуального среза данных из базы-источника

Чтобы не выгружать неактуальные исторические движения периодического регистра, обратимся к ПВД (Правилу выгрузки данных). В обработчике «Перед обработкой» или «Перед выгрузкой данных» сформируем выборку актуальных данных через виртуальную таблицу СрезПоследних.


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

Запрос.УстановитьПараметр("Период", ТекущаяДатаСеанса());
Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    ВходящиеДанные = Новый Структура("Номенклатура, Сегмент");
    ЗаполнитьЗначенияСвойств(ВходящиеДанные, Выборка);
    ВыгрузитьПоПравилу(,, ВходящиеДанные,, "СегментыНоменклатуры");
КонецЦикла;

Шаг 2. Обработка загрузки и очистка набора записей в базе-приемнике

Рассмотрим основной способ решения задачи непосредственно при загрузке. Для этого используем обработчик «После загрузки» правила конвертации объектов (ПКО) целевого регистра.

В этом обработчике сопоставление ссылок базы Б уже завершено: переменная Объект содержит найденные ссылки на номенклатуру и сегмент. Мы можем применить объект РегистрСведенийНаборЗаписей, записать требуемое состояние вручную и отменить стандартную запись движка обмена с помощью флага Отказ = Истина.

Посмотрим на пример кода в обработчике «После загрузки» ПКО:


// Отменяем стандартную запись объекта платформой КД
Отказ = Истина;

Если Не ЗначениеЗаполнено(Объект.Номенклатура) Тогда
    Возврат;
КонецЕсли;

// Создаем набор записей с отбором по текущей номенклатуре
Набор = РегистрыСведений.СегментыНоменклатуры.СоздатьНаборЗаписей();
Набор.Отбор.Номенклатура.Установить(Объект.Номенклатура);

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

// При пустом наборе (если был "Без сегмента") запись с замещением удалит все старые строки.
// Если сегмент валидный — старые записи сотрутся, а новая единственная строка добавится.
Набор.Записать(Истина);

Шаг 3. Оптимизация для больших объемов данных

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

  1. В обработчике конвертации «ПередЗагрузкойДанных» инициализируем таблицу значений:
    
    Параметры.Вставить("ТаблицаСегментов", Новый ТаблицаЗначений);
    Параметры.ТаблицаСегментов.Колонки.Добавить("Номенклатура");
    Параметры.ТаблицаСегментов.Колонки.Добавить("Сегмент");
    Параметры.ТаблицаСегментов.Колонки.Добавить("УдалитьЗаписи", Новый ОписаниеТипов("Булево"));
    
  2. В ПКО регистра в обработчике «После загрузки» только наполняем эту таблицу и выставляем Отказ = Истина:
    
    Отказ = Истина;
    
    СтрокаТЗ = Параметры.ТаблицаСегментов.Добавить();
    СтрокаТЗ.Номенклатура = Объект.Номенклатура;
    СтрокаТЗ.Сегмент = Объект.Сегмент;
    
    Если Не ЗначениеЗаполнено(Объект.Сегмент) Или СокрЛП(Объект.Сегмент.Наименование) = "Без сегмента" Тогда
        СтрокаТЗ.УдалитьЗаписи = Истина;
    Иначе
        СтрокаТЗ.УдалитьЗаписи = Ложь;
    КонецЕсли;
    
  3. В обработчике конвертации «ПослеЗагрузкиДанных» пакетно обрабатываем накопленные строки:
    
    ТЗ = Параметры.ТаблицаСегментов;
    ТЗ.Свернуть("Номенклатура, Сегмент, УдалитьЗаписи");
    
    Для Каждого Стр Из ТЗ Цикл
        Набор = РегистрыСведений.СегментыНоменклатуры.СоздатьНаборЗаписей();
        Набор.Отбор.Номенклатура.Установить(Стр.Номенклатура);
        
        Если Не Стр.УдалитьЗаписи Тогда
            НоваяЗапись = Набор.Добавить();
            НоваяЗапись.Номенклатура = Стр.Номенклатура;
            НоваяЗапись.Сегмент = Стр.Сегмент;
        КонецЕсли;
        
        Набор.Записать(Истина);
    КонецЦикла;
    

Таким образом, использование наборов записей с отбором по ключевому измерению Номенклатура и замещением позволяет одновременно решить проблему разницы измерений регистра и корректно обработать очистку записей при передаче специального значения Без сегмента.

← На главную