В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача клонирования существующих записей в регистрах сведений. Например, когда необходимо создать точно такую же запись, но для другого контрагента, организации или на другую дату (в случае периодических регистров), сохранив при этом десятки заполненных ресурсов и реквизитов. В этой статье мы подробно разберем, как реализовать «размножение» записей эффективно, избегая ручного перечисления всех полей.
Это самый распространенный и наглядный способ для копирования одной конкретной записи. Суть метода заключается в том, чтобы прочитать существующую запись в объект РегистрСведенийМенеджерЗаписи, а затем перенести её данные в новый объект того же типа. Разберем этот процесс по шагам.
Для начала нам необходимо инициализировать менеджер записи для чтения оригинала. Мы устанавливаем значения всех измерений, которые однозначно идентифицируют запись, и вызываем метод Прочитать(). Проанализируем пример кода:
// 1. Читаем исходную запись
ИсходнаяЗапись = РегистрыСведений.ИмяВашегоРегистра.СоздатьМенеджерЗаписи();
ИсходнаяЗапись.Измерение1 = ЗначениеИзмерения1;
ИсходнаяЗапись.Измерение2 = ЗначениеИзмерения2;
ИсходнаяЗапись.Прочитать();
Если ИсходнаяЗапись.Выбран() Тогда
// 2. Создаем объект для новой записи
НоваяЗапись = РегистрыСведений.ИмяВашегоРегистра.СоздатьМенеджерЗаписи();
// 3. Копируем данные из старой записи в новую
// Используем четвертый параметр, чтобы НЕ копировать то измерение, которое хотим изменить
ЗаполнитьЗначенияСвойств(НоваяЗапись, ИсходнаяЗапись, , "Измерение2");
// 4. Устанавливаем новое значение для изменяемого измерения
НоваяЗапись.Измерение2 = НовоеЗначениеИзмерения2;
// 5. Записываем результат
НоваяЗапись.Записать();
КонецЕсли;
Важный момент, на который стоит обратить внимание: использование четвертого параметра функции ЗаполнитьЗначенияСвойств. Если вы сначала присвоите НоваяЗапись.Измерение2 = НовоеЗначение, а потом вызовете заполнение без списка исключений, то старое значение из ИсходнаяЗапись затрет ваше новое значение. Поэтому правильнее либо указывать исключения, либо выполнять присваивание после копирования свойств.
Если перед нами стоит задача скопировать не одну запись, а целую группу (например, перенести все настройки одного пользователя на другого), использование менеджера записи в цикле будет крайне неэффективным. В такой ситуации мы проанализируем возможности объекта РегистрСведенийНаборЗаписей.
Рассмотрим алгоритм действий:
Выгрузить().Посмотрим на программную реализацию этой логики:
// Устанавливаем отбор для исходных данных
НаборИсходный = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборИсходный.Отбор.Организация.Установить(СтараяОрганизация);
НаборИсходный.Прочитать();
// Выгружаем в таблицу значений
ТаблицаДанных = НаборИсходный.Выгрузить();
// Массово меняем значение измерения в таблице
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
СтрокаДанных.Организация = НоваяОрганизация;
КонецЦикла;
// Создаем новый набор для записи (без отбора или с новым отбором)
НаборНовый = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборНовый.Отбор.Организация.Установить(НоваяОрганизация);
// Загружаем модифицированные данные
НаборНовый.Загрузить(ТаблицаДанных);
НаборНовый.Записать(Истина); // Истина означает замещение данных в рамках отбора
Этот способ значительно быстрее, так как платформа выполняет запись данных одним пакетом, что минимизирует количество обращений к СУБД. Однако помните, что метод Записать(Истина) удалит все старые записи в регистре, которые попадают под новый отбор, перед записью новых.
Если мы работаем с периодическим регистром сведений, то к списку ключевых полей добавляется стандартный реквизит Период. При копировании записи на новую дату нам достаточно изменить только это свойство. Выясним причину возможных ошибок: если в регистре включен режим «Подчинение регистратору», то использование МенеджерЗаписи напрямую невозможно. В этом случае копирование осуществляется только через документы-регистраторы или путем корректировки наборов записей с отбором по конкретному регистратору.
При программном создании копий велика вероятность столкнуться с ошибкой нарушения уникальности. Поскольку регистр сведений не допускает существования двух записей с одинаковыми значениями всех измерений (и периода), перед выполнением Записать() стоит убедиться, что такая запись еще не существует. Проанализируем пример безопасной записи:
Попытка
НоваяЗапись.Записать();
Исключение
Сообщить("Не удалось скопировать запись: " + ОписаниеОшибки());
// Здесь можно реализовать логику обновления существующей записи,
// если это предусмотрено бизнес-логикой
КонецПопытки;
Иногда удобно использовать промежуточную структуру для переноса данных. Это полезно, если вы получаете данные для копирования не через объект Прочитать(), а с помощью запроса. Результат выполнения запроса можно легко преобразовать в структуру, а затем применить ЗаполнитьЗначенияСвойств к новому менеджеру записи. Это делает код более «чистым» и позволяет избежать лишних блокировок таблиц базы данных при чтении тяжелых объектов.
Подводя итог, можно сказать, что выбор метода зависит от объема данных. Для разовых операций МенеджерЗаписи с функцией ЗаполнитьЗначенияСвойств является «золотым стандартом» благодаря своей простоте и читаемости. Для пакетной обработки данных всегда следует отдавать предпочтение Набору записей с использованием таблиц значений.