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