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

Программист IT и автоматизация бизнеса
← На главную

Перенос данных между регистрами с разной структурой — одна из классических задач при работе с конфигурацией «1С:Конвертация данных 2.1» (КД 2.1). Особенно часто возникают сложности при попытке перегрузить данные из подчиненного регистра (где записи жестко привязаны к регистратору) в независимый регистр. Проблема заключается в том, что по умолчанию система пытается выгружать записи Источника как отдельные объекты РегистрСведенийЗапись, в то время как Получатель ожидает формат РегистрСведенийНаборЗаписей для корректной записи в базу.

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

В чем заключается сложность трансформации структуры?

Проанализируем ситуацию: в Источнике записи регистра существуют только в контексте документа-регистратора. Когда мы настраиваем обычное правило выгрузки, КД пытается сопоставить поля. Однако для независимого регистра в Получателе критически важен отбор по измерениям. Если просто передать набор полей, загрузка может пройти некорректно: данные могут не записаться, либо затереть существующие записи, которые не должны были пострадать. Нам необходимо заставить конвертацию сформировать XML-пакет, который выглядит как полноценный набор записей с установленным отбором.

Решение проблемы через функцию ВыгрузитьРегистр

Для решения этой задачи воспользуемся произвольным алгоритмом в ПВД. Рассмотрим пошагово, как реализовать этот механизм. Нам потребуется имитировать структуру набора записей, которую ожидает платформа 1С при загрузке.

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


// 1. Формируем искусственную структуру-шаблон, аналогичную РегистрСведенийНаборЗаписей
Строки = Новый ТаблицаЗначений;
Строки.Колонки.Добавить("Период");
Строки.Колонки.Добавить("Номенклатура");
Строки.Колонки.Добавить("ФорматМагазина");
Строки.Колонки.Добавить("РазрешеныЗакупки");
Строки.Колонки.Добавить("РазрешеныПродажи");
Строки.Колонки.Добавить("Активность");
Строки.Колонки.Добавить("Документ");
// Добавляем пустую строку, которую будем заполнять в цикле
Строки.Добавить();

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

СтрокаОтбора = Отбор.Добавить();
СтрокаОтбора.Имя = "Номенклатура";
СтрокаОтбора.Использование = Истина;

СтрокаОтбора = Отбор.Добавить();
СтрокаОтбора.Имя = "ФорматМагазина";
СтрокаОтбора.Использование = Истина;

// 3. Собираем итоговый шаблон
ШаблонНЗ = Новый Сруктура("Отбор, Строки");
ШаблонНЗ.Отбор = Отбор;
ШаблонНЗ.Строки = Строки;    

// 4. Основной цикл по выгружаемым данным
// Объект в данном контексте — это выборка записей из Источника
Для каждого Запись из Объект Цикл
    // Копируем шаблон (используем ЗначениеВСтрокуВнутр для глубокого копирования структуры)
    НЗ = ЗначениеИзСтрокиВнутр(ЗначениеВСтрокуВнутр(ШаблонНЗ));
    
    // Заполняем значения отбора для текущей записи
    СтрокаОтбораНом = НЗ.Отбор.Найти("Номенклатура", "Имя");
    СтрокаОтбораНом.Значение = Запись.Номенклатура;
    
    СтрокаОтбораФормат = НЗ.Отбор.Найти("ФорматМагазина", "Имя");
    СтрокаОтбораФормат.Значение = Запись.ОбъектПланирования; // Пример маппинга полей
    
    // Заполняем данные самой записи
    СтрокаНабора = НЗ.Строки[0];
    ЗаполнитьЗначенияСвойств(СтрокаНабора, Запись);
    
    // Ручная корректировка полей, если имена в Источнике и Получателе отличаются
    СтрокаНабора.ФорматМагазина = Запись.ОбъектПланирования;
    СтрокаНабора.Документ = СокрЛП(Объект.Отбор.Регистратор.Значение);
    
    // 5. Вызываем встроенную функцию КД для выгрузки в XML
    // Параметры: (НаборДанных, ИмяПКО, ВходящиеДанные, ИсходящиеДанные, ИмяПВД)
    ВыгрузитьРегистр(НЗ, , , , "АссортиментДТС");
КонецЦикла;

Проанализируем ключевые моменты алгоритма

Рассмотрим подробнее, почему этот код решает проблему:

  1. Структура таблиц: Функция ВыгрузитьRegистр требует строго определенного формата первого параметра. Это должна быть структура с ключами Отбор и Строки. Обе таблицы должны содержать колонки, соответствующие метаданным регистра в Получателе.
  2. Работа с отбором: Когда мы указываем СтрокаОтбора.Использование = Истина, мы сообщаем платформе при загрузке, что перед записью этого набора нужно удалить старые данные в Получателе, соответствующие этому фильтру. Это критически важно для предотвращения дублей в независимых регистрах.
  3. Маппинг полей: Обратите внимание на строку СтрокаНабора.ФорматМагазина = Запись.ОбъектПланирования. Поскольку структуры разные, мы можем на лету переопределять, какие данные из Источника попадут в конкретные измерения Получателя.
  4. Функция копирования: Использование ЗначениеВСтрокуВнутр позволяет быстро получить чистую копию шаблона структуры для каждой итерации цикла. Однако, если записей очень много (десятки тысяч), рассмотрим более производительный вариант — просто очищать таблицы внутри цикла вместо пересоздания структуры.

Важные настройки в Правилах Конвертации Объектов (ПКО)

Одного программного кода в ПВД недостаточно. Проанализируем настройки ПКО, которое используется для загрузки этого регистра (в нашем примере это АссортиментДТС):

Оптимизация производительности при больших объемах данных

Выясним причину возможного замедления процесса. Сериализация в строку (ЗначениеВСтрокуВнутр) внутри цикла — ресурсоемкая операция. Если вы переносите сотни тысяч записей, лучше изменить подход:

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

Также помните про периодичность. Если регистр в Получателе периодический, поле Период в таблице Строки является обязательным для заполнения. Если в Источнике период брался из даты документа, не забудьте явно присвоить это значение: СтрокаНабора.Период = Запись.Регистратор.Дата.

Резюме

Мы разобрали, как осуществить перенос из подчиненного регистра в независимый, «обманув» стандартные механизмы выгрузки с помощью создания искусственного набора записей. Использование функции ВыгрузитьРегистр в сочетании с ручным формированием таблиц Отбор и Строки дает программисту полный контроль над тем, как данные будут записаны в целевую базу, гарантируя целостность и отсутствие дубликатов.

← На главную