Как исправить ошибку «Запись с такими ключевыми полями существует» при перезаписи значения в регистре сведений 1С

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

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

Выясним причину ошибки

Проанализируем исходный код, который вызывает исключение:


НаборЗаписей = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьНаборЗаписей(); 
НаборЗаписей.Отбор.Объект.Установить(Выборка.Ссылка);
НаборЗаписей.Отбор.Свойство.Установить(Свойство);
НаборЗаписей.Прочитать();

НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Объект = Выборка.Ссылка;
НоваяЗапись.Свойство = Свойство;
НоваяЗапись.Значение = Выборка.Ссылка.БрендИнтернетМагазин; 

НаборЗаписей.Записать(Истина);

Ошибка возникает еще до момент сохранения данных в базу — на этапе внутренней проверки уникальности ключевых полей в оперативной памяти 1С. Метод Прочитать() загружает из базы данных текущую запись, соответствующую установленному отбору. В этот момент в объекте НаборЗаписей уже находится одна строка с комбинацией измерений Объект и Свойство.

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

Способ 1. Использование Менеджера записи (Рекомендуемый подход)

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

Рассмотрим пример кода с использованием менеджера записи:


МенеджерЗаписи = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = Выборка.Ссылка;
МенеджерЗаписи.Свойство = Свойство;
МенеджерЗаписи.Значение = Выборка.БрендИнтернетМагазин;

МенеджерЗаписи.Записать(); // Второстепенный параметр Замещать по умолчанию равен Истина

При таком подходе платформа самостоятельно проверит наличие записи в базе данных: если она уже существует — обновит ее ресурсы, если нет — создаст новую.

Способ 2. Изменение существующей строки в Наборе записей

Если необходимо остаться в рамках логики работы с объектом НаборЗаписей, следует сначала проверить, была ли прочитана существующая запись из базы. Если запись уже есть в наборе — меняем её ресурс, если набор пуст — добавляем новую строку.

Разберем реализацию этого алгоритма на примере:


НаборЗаписей = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьНаборЗаписей(); 
НаборЗаписей.Отбор.Объект.Установить(Выборка.Ссылка);
НаборЗаписей.Отбор.Свойство.Установить(Свойство);
НаборЗаписей.Прочитать();

Если НаборЗаписей.Количество() > 0 Тогда 
    // Поскольку отбор установлен по всем измерениям, в наборе может быть только одна запись
    Запись = НаборЗаписей[0]; 
Иначе
    Запись = НаборЗаписей.Добавить();
    Запись.Объект = Выборка.Ссылка;
    Запись.Свойство = Свойство;
КонецЕсли;

Запись.Значение = Выборка.БрендИнтернетМагазин; 
НаборЗаписей.Записать(Истина);

Способ 3. Очистка набора перед добавлением

Если мы хотим принудительно перезаписать данные, не проверяя содержимое набора, можно очистить прочитанный набор с помощью метода Очистить() либо вовсе отказаться от вызова Прочитать():


НаборЗаписей = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьНаборЗаписей(); 
НаборЗаписей.Отбор.Объект.Установить(Выборка.Ссылка);
НаборЗаписей.Отбор.Свойство.Установить(Свойство);

// Чтение не выполняем, сразу добавляем запись в пустой набор
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Объект = Выборка.Ссылка;
НоваяЗапись.Свойство = Свойство;
НоваяЗапись.Значение = Выборка.БрендИнтернетМагазин; 

// Параметр Замещать = Истина (по умолчанию) перезапишет существующую запись в БД
НаборЗаписей.Записать(Истина);

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

Посмотрим на дополнительные аспекты, которые необходимо учитывать при работе с регистрами сведений:

  1. Оптимизация обращений к данным (Разыменование ссылок): Обращение вида Выборка.Ссылка.БрендИнтернетМагазин вызывает неявный дополнительный SQL-запрос к базе данных при каждом обращении к полю через точку от ссылки. Извлекайте поле БрендИнтернетМагазин непосредственно в тексте запроса и обращайтесь к нему напрямую: Выборка.БрендИнтернетМагазин.
  2. Стандарты БСП для дополнительных реквизитов: Регистр ЗначенияСвойствОбъектов в типовых конфигурациях управляется механизмом Библиотеки Стандартных Подсистем. При прямой записи данные в кэше могут не обновиться. По возможности используйте стандартный программный интерфейс БСП — метод УправлениеСвойствами.ЗаписатьСвойстваУОбъекта().
  3. Периодические и подчиненные регистры: Если регистр является периодическим, ключевым полем также становится Период. Для подчиненных регистратору регистров сведений прямое использование СоздатьМенеджерЗаписи() невозможно — запись производится только через набор с обязательным отбором по документу-регистратору.
← На главную