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

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

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

Понимание природы набора записей

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

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

Шаг 1: Анализ исходных данных в документе

Как показывает практика, в 90% случаев проблема кроется в данных объекта-источника (например, табличной части документа). Если в документе присутствуют две одинаковые строки (одна и та же номенклатура, склад, характеристика), то при проведении они превратятся в две одинаковые записи в наборе.

Рассмотрим пример кода, который часто становится источником проблем:


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

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

Шаг 2: Использование отладки для поиска «невидимых» дублей

Если мы не видим дублей в коде, нам поможет отладчик. Разберем по шагам процесс диагностики:

  1. Установим точку останова на строке НаборЗаписей.Записать().
  2. В окне «Вычислить выражение» проверим количество записей в наборе: НаборЗаписей.Количество().
  3. Воспользуемся методом выгрузки набора в таблицу значений для быстрого анализа: НаборЗаписей.Выгрузить(). Полученную таблицу можно просмотреть визуально или сохранить в файл для детального изучения.
  4. Если записей много, воспользуемся методом свертки в консоли отладки, чтобы подтвердить наличие дублей.

Шаг 3: Программное устранение дублей через таблицу значений

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


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

// Сначала подготавливаем таблицу данных
ТЗ_Движений = Новый ТаблицаЗначений;
ТЗ_Движений.Колонки.Добавить("Период");
ТЗ_Движений.Колонки.Добавить("Номенклатура");
ТЗ_Движений.Колонки.Добавить("Штрихкод");
ТЗ_Движений.Колонки.Добавить("Регистратор");

Для Каждого Проводка Из МассивПроводок Цикл
    НоваяСтрока = ТЗ_Движений.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Проводка);
    НоваяСтрока.Период = ДатаДокумента;
    НоваяСтрока.Регистратор = Ссылка;
КонецЦикла;

// ВАЖНО: Сворачиваем по всем измерениям и периоду
ТЗ_Движений.Свернуть("Период, Номенклатура, Штрихкод, Регистратор");

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

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

Шаг 4: Анализ редких технических причин (SQL и кэш)

Бывают случаи, когда программный код идеален, дублей в наборе нет, а ошибка все равно возникает. Проанализируем более глубокие причины:

1. Невидимые символы в строковых измерениях. Если одно из измерений — строка, в него могут попасть непечатные символы (неразрывный пробел, перевод строки). В Excel или консоли запросов записи "Товар" и "Товар " выглядят одинаково, но для SQL и платформы 1С это разные значения. Однако при определенных настройках кодировки базы данных (Case Insensitivity) или при попытке записи система может посчитать их конфликтующими.

2. Проблемы с индексами на уровне SQL Server. В редких случаях (особенно при сбоях питания или аварийном завершении работы сервера) индексы таблицы регистра могут «расползтись». В такой ситуации 1С не видит запись, а SQL при попытке вставки выдает ошибку нарушения уникального ключа. Решение — выполнение реиндексации через конфигуратор (Тестирование и исправление) или средствами СУБД.

3. Миллисекунды в периоде. Платформа 1С работает с точностью до секунды, но в некоторых интеграционных сценариях в поле Период могут попасть значения с миллисекундами. При сравнении в 1С они могут выглядеть одинаковыми, но при записи вызывать коллизии. Всегда полезно нормализовать дату с помощью функции КонецСекунды() или НачалоСекунды().

Рекомендации по профилактике ошибки

Чтобы минимизировать риск возникновения проблем с уникальностью записей, придерживайтесь следующих правил:

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

← На главную