Как эффективно скопировать данные одного регистра сведений в другой в 1С:Предприятие 8?

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

Мы часто сталкиваемся с необходимостью перенести данные из одного регистра сведений в другой. Это может потребоваться при изменении структуры метаданных, оптимизации хранения информации, объединении или разделении регистров. Давайте вместе разберем различные подходы к решению этой задачи, от простых до более сложных, и выясним, какой из них подойдет именно в вашей ситуации. В этой статье мы подробно рассмотрим несколько эффективных методов копирования данных регистра сведений, используя как встроенные механизмы платформы 1С, так и специализированные инструменты, такие как простой менеджер данных (simple data manager).

1. Программное копирование с использованием объектов "НаборЗаписей" и "МенеджерЗаписи"

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

1.1. Копирование с помощью объекта "НаборЗаписей"

Метод с использованием объекта НаборЗаписей идеально подходит для массового копирования или изменения данных. Представим, что у нас есть исходный регистр сведений РегистрСведенийИсходный и целевой регистр РегистрСведенийЦелевой. Разберем процесс по шагам:

  1. Получаем менеджер записи целевого регистра: Мы создаем объект НаборЗаписей для регистра, в который будем копировать данные.
  2. Очищаем целевой регистр (опционально): Если нам нужно полностью перезаписать данные в целевом регистре, мы можем сначала очистить его.
  3. Читаем данные из исходного регистра: Мы используем объект НаборЗаписей исходного регистра для чтения всех или части записей.
  4. Перебираем и записываем данные: Перебираем каждую запись из прочитанного набора и добавляем ее в набор записей целевого регистра, при необходимости изменяя значения измерений или ресурсов.
  5. Записываем набор записей: Вызываем метод Записать() для объекта НаборЗаписей целевого регистра. Эта операция записывает все добавленные записи.

Посмотрим на пример кода:


Функция КопироватьРегистрСведенийНаборЗаписей()
    Попытка
        // 1. Создаем набор записей для исходного регистра
        МенеджерЗаписиИсходный = РегистрыСведений.РегистрСведенийИсходный;
        НаборЗаписейИсходный = МенеджерЗаписиИсходный.СоздатьНаборЗаписей();
        НаборЗаписейИсходный.Прочитать(); // Читаем все записи исходного регистра

        // 2. Создаем набор записей для целевого регистра
        МенеджерЗаписиЦелевой = РегистрыСведений.РегистрСведенийЦелевой;
        НаборЗаписейЦелевой = МенеджерЗаписиЦелевой.СоздатьНаборЗаписей();
        
        // Опционально: если нужно очистить целевой регистр перед копированием
        // НаборЗаписейЦелевой.Очистить(); 
        
        // 3. Перебираем записи исходного регистра и добавляем их в целевой
        Для Каждого ЗаписьИсходная Из НаборЗаписейИсходный Цикл
            НоваяЗапись = НаборЗаписейЦелевой.Добавить();
            
            // Заполняем измерения и ресурсы.
            // Предполагаем, что измерения и ресурсы имеют одинаковые имена и типы.
            НоваяЗапись.Измерение1 = ЗаписьИсходная.Измерение1;
            НоваяЗапись.Измерение2 = ЗаписьИсходная.Измерение2;
            НоваяЗапись.Ресурс1 = ЗаписьИсходная.Ресурс1;
            НоваяЗапись.Ресурс2 = ЗаписьИсходная.Ресурс2;
            
            // Если регистр периодический, не забываем про Период
            Если МенеджерЗаписиИсходный.Метаданные().Периодичность <> Метаданные.Перечисления.Периодичность.Непериодический Тогда
                НоваяЗапись.Период = ЗаписьИсходная.Период;
            КонецЕсли;

            // Если регистр подчинен регистратору, не забываем про Регистратор
            Если МенеджерЗаписиИсходный.Метаданные().Подчиненность <> Метаданные.Перечисления.ПодчиненностьРегистраСведений.Независимый Тогда
                НоваяЗапись.Регистратор = ЗаписьИсходная.Регистратор;
            КонецЕсли;
        КонецЦикла;

        // 4. Записываем набор записей в целевой регистр
        НаборЗаписейЦелевой.Записать();
        Сообщить("Данные успешно скопированы.");
        Возврат Истина;
    Исключение
        Сообщить("Ошибка при копировании данных: " + ОписаниеОшибки());
        Возврат Ложь;
    КонецПопытки;
КонецФункции

1.2. Копирование с помощью объекта "МенеджерЗаписи"

Если требуется скопировать или изменить одну конкретную запись, или если нам нужно более гранулированное управление записью (например, проверка перед каждой записью), мы можем использовать МенеджерЗаписи. Разберем процесс по шагам:

  1. Выбираем данные из исходного регистра: Мы можем использовать запрос или тот же НаборЗаписей для получения записей из исходного регистра.
  2. Создаем объект "МенеджерЗаписи" для каждой записи: Для каждой записи, которую мы хотим скопировать, создаем новый объект МенеджерЗаписи целевого регистра.
  3. Заполняем значения: Заполняем значения измерений и ресурсов нового менеджера записи.
  4. Записываем запись: Вызываем метод Записать(). Если запись с такими же значениями измерений уже существует, она будет обновлена; в противном случае будет создана новая запись.

Пример использования с запросом:


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

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

1.3. Использование запроса в "ТаблицуЗначений" и "ЗаполнитьЗначенияСвойств()"

Этот подход объединяет преимущества запросов для выборки данных и удобство работы с ТаблицейЗначений. Он особенно эффективен, когда имена полей в исходном и целевом регистрах совпадают. Разберем по шагам:

  1. Выполняем запрос: Создаем запрос, который выбирает все необходимые данные из исходного регистра сведений. Результат запроса выгружаем в ТаблицуЗначений.
  2. Итерируем по "ТаблицеЗначений": Перебираем каждую строку полученной таблицы.
  3. Создаем "МенеджерЗаписи" или запись "НабораЗаписей": Для каждой строки таблицы создаем новый МенеджерЗаписи для целевого регистра или добавляем новую запись в НаборЗаписей.
  4. Заполняем значения: Используем метод ЗаполнитьЗначенияСвойств() для быстрого переноса значений из строки ТаблицыЗначений в объект МенеджерЗаписи или запись НабораЗаписей. Это работает, если имена полей совпадают.
  5. Записываем данные: Если используем МенеджерЗаписи, записываем каждую запись по отдельности. Если НаборЗаписей, добавляем записи в набор и записываем его в конце.

Посмотрим на пример:


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

        НаборЗаписейЦелевой = РегистрыСведений.РегистрСведенийЦелевой.СоздатьНаборЗаписей();
        // Опционально: НаборЗаписейЦелевой.Очистить(); 

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

2. Копирование через XML-выгрузку/загрузку с модификацией метаданных

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

  1. Создайте копию регистра: В режиме конфигуратора скопируйте исходный регистр сведений и дайте ему новое имя. Убедитесь, что структуры совпадают.
  2. Выгрузите данные в XML: Используя универсальный обмен данными XML 8.2 и 8.3 или стандартные средства, выгрузите данные из исходного регистра сведений в XML-файл. Если конфигурации не полностью идентичны, стоит применить адаптивную выгрузку и загрузку данных XML с гибкими отборами.
  3. Отредактируйте XML-файл: Откройте полученный XML-файл в текстовом редакторе. Найдите все упоминания имени исходного регистра и замените их на имя целевого регистра. Будьте внимательны, чтобы не повредить структуру XML.
  4. Загрузите данные из XML: Используйте для этого выгрузку и загрузку данных XML с дополнительными опциями, которые позволяют выполнять поиск по полям и фильтровать независимые регистры.
  5. Добавьте недостающие колонки (если необходимо): Если целевой регистр имеет дополнительные измерения или ресурсы, их придется заполнять отдельно после загрузки данных.

Этот метод требует особой осторожности при редактировании XML-файла, так как любая ошибка может привести к невозможности загрузки данных.

3. Использование Системы Компоновки Данных (СКД) и запросов

Хотя СКД чаще используется для построения отчетов, ее можно адаптировать для получения данных в ТаблицуЗначений, которую затем можно использовать для записи в регистр. Разберем по шагам:

  1. Создайте схему компоновки данных: Внешняя обработка или модуль должен содержать схему компоновки данных с запросом к исходному регистру.
  2. Настройте компоновщик макета: Используйте объекты КомпоновщикМакетаКомпоновкиДанных и ПроцессорКомпоновкиДанных.
  3. Выведите результат в "ТаблицуЗначений": Используйте ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений.
  4. Запишите данные: Далее переберите полученную ТаблицуЗначений и запишите данные в целевой регистр, как было описано ранее.

Посмотрим на пример кода:


Функция КопироватьРегистрСведенийЧерезСКД()
    Попытка
        СхемаКомпоновкиДанных = ПолучитьМакет("МояСхемаКомпоновкиДанных");
        КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
        КомпоновщикНастроек.Инициализировать(СхемаКомпоновкиДанных);

        КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных();
        МакетКомпоновкиДанных = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(),,,Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
        
        ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
        ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных,,,);
        
        ТаблицаДанныхСКД = Новый ТаблицаЗначений;
        ПроцессорВыводаРезультатаКомпоновкиДанных = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
        ПроцессорВыводаРезультатаКомпоновкиДанных.УстановитьОбъект(ТаблицаДанныхСКД);
        ПроцессорВыводаРезультатаКомпоновкиДанных.Вывести(ПроцессорКомпоновкиДанных);
        
        НачатьТранзакцию(); 
        НаборЗаписейЦелевой = РегистрыСведений.РегистрСведенийЦелевой.СоздатьНаборЗаписей();
        Для Каждого СтрокаТЗ Из ТаблицаДанныхСКД Цикл
            НоваяЗапись = НаборЗаписейЦелевой.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяЗапись, СтрокаТЗ);
        КонецЦикла;
        НаборЗаписейЦелевой.Записать();
        
        ФиксироватьТранзакцию();
        Сообщить("Данные успешно скопированы через СКД.");
        Возврат Истина;
    Исключение
        ОтменитьТранзакцию();
        Сообщить("Ошибка при копировании данных через СКД: " + ОписаниеОшибки());
        Возврат Ложь;
    КонецПопытки;
КонецФункции

4. Применение типовой конфигурации "Конвертация данных" (КД 2.1)

Для более сложных сценариев, особенно при переносе данных между различными конфигурациями или базами данных, мы можем использовать специализированную конфигурацию "Конвертация данных". * Когда использовать: Этот инструмент незаменим, когда требуется сложная трансформация данных, пересчет значений или сопоставление ссылочных объектов между базами с разными GUID. * Как это работает: Мы определяем правила выгрузки для каждого поля исходного регистра и правила загрузки для целевого, указывая алгоритмы сопоставления. * Нюансы: Настройка правил может занять значительное время, но это лучшее решение для регулярных обменов или переноса данных в сильно измененные структуры.

5. Использование универсальных обработок для переноса данных

Для ускорения работы часто применяются готовые инструменты. Например, универсальный перенос данных между разными конфигурациями 1С 8.3 позволяет копировать информацию по технологии COM+HTTP без создания промежуточных файлов. * Преимущества: Такие инструменты, как простой менеджер данных, предоставляют удобный интерфейс для выбора регистров и массовой загрузки миллионов записей за считанные минуты. * Безопасность: Если вам необходимо передать данные в зашифрованном виде, воспользуйтесь универсальной выгрузкой-загрузкой с возможностью шифрования. * Важное условие: Для корректного "один к одному" копирования структуры регистров должны быть максимально схожи.

Важные рекомендации и аспекты

При выполнении любых операций по копированию данных, мы настоятельно рекомендуем учитывать следующие моменты: * Резервное копирование: Всегда делайте резервную копию базы данных. Это ваша страховка. * Тестирование: Проверяйте работу методов на копии базы. * Транзакции: Используйте НачатьТранзакцию() и ФиксироватьТранзакцию() для обеспечения целостности. * Оптимизация запросов: Для больших объемов данных оптимизируйте выборку и используйте индексы. * Тип регистра: Не забывайте про специфику: в периодических регистрах важно поле Период, а в подчиненных — Регистратор. * Валидация: Перед записью убедитесь в корректности заполнения всех ключевых полей.

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

← На главную