Как программно скопировать запись регистра сведений с изменением одного измерения?

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

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

Метод 1: Использование Менеджера записи и функции ЗаполнитьЗначенияСвойств

Это самый распространенный и наглядный способ для копирования одной конкретной записи. Суть метода заключается в том, чтобы прочитать существующую запись в объект РегистрСведенийМенеджерЗаписи, а затем перенести её данные в новый объект того же типа. Разберем этот процесс по шагам.

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


// 1. Читаем исходную запись
ИсходнаяЗапись = РегистрыСведений.ИмяВашегоРегистра.СоздатьМенеджерЗаписи();
ИсходнаяЗапись.Измерение1 = ЗначениеИзмерения1;
ИсходнаяЗапись.Измерение2 = ЗначениеИзмерения2;
ИсходнаяЗапись.Прочитать();

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

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

Метод 2: Массовое копирование через Набор записей и Таблицу значений

Если перед нами стоит задача скопировать не одну запись, а целую группу (например, перенести все настройки одного пользователя на другого), использование менеджера записи в цикле будет крайне неэффективным. В такой ситуации мы проанализируем возможности объекта РегистрСведенийНаборЗаписей.

Рассмотрим алгоритм действий:

  1. Создаем набор записей с отбором по исходным критериям.
  2. Выгружаем данные в таблицу значений методом Выгрузить().
  3. Модифицируем колонку с нужным измерением прямо в таблице значений.
  4. Загружаем таблицу в новый набор записей и сохраняем.

Посмотрим на программную реализацию этой логики:


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

// Выгружаем в таблицу значений
ТаблицаДанных = НаборИсходный.Выгрузить();

// Массово меняем значение измерения в таблице
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
    СтрокаДанных.Организация = НоваяОрганизация;
КонецЦикла;

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

// Загружаем модифицированные данные
НаборНовый.Загрузить(ТаблицаДанных);
НаборНовый.Записать(Истина); // Истина означает замещение данных в рамках отбора

Этот способ значительно быстрее, так как платформа выполняет запись данных одним пакетом, что минимизирует количество обращений к СУБД. Однако помните, что метод Записать(Истина) удалит все старые записи в регистре, которые попадают под новый отбор, перед записью новых.

Особенности периодических регистров

Если мы работаем с периодическим регистром сведений, то к списку ключевых полей добавляется стандартный реквизит Период. При копировании записи на новую дату нам достаточно изменить только это свойство. Выясним причину возможных ошибок: если в регистре включен режим «Подчинение регистратору», то использование МенеджерЗаписи напрямую невозможно. В этом случае копирование осуществляется только через документы-регистраторы или путем корректировки наборов записей с отбором по конкретному регистратору.

Контроль уникальности и обработка исключений

При программном создании копий велика вероятность столкнуться с ошибкой нарушения уникальности. Поскольку регистр сведений не допускает существования двух записей с одинаковыми значениями всех измерений (и периода), перед выполнением Записать() стоит убедиться, что такая запись еще не существует. Проанализируем пример безопасной записи:


Попытка
    НоваяЗапись.Записать();
Исключение
    Сообщить("Не удалось скопировать запись: " + ОписаниеОшибки());
    // Здесь можно реализовать логику обновления существующей записи, 
    // если это предусмотрено бизнес-логикой
КонецПопытки;

Использование промежуточной структуры

Иногда удобно использовать промежуточную структуру для переноса данных. Это полезно, если вы получаете данные для копирования не через объект Прочитать(), а с помощью запроса. Результат выполнения запроса можно легко преобразовать в структуру, а затем применить ЗаполнитьЗначенияСвойств к новому менеджеру записи. Это делает код более «чистым» и позволяет избежать лишних блокировок таблиц базы данных при чтении тяжелых объектов.

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

← На главную