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