Почему при программном создании элемента справочника возникает ошибка «Код не уникален» и как ее исправить?

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

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

Разберем причины возникновения такого поведения платформы 1С и выясним, как правильно восстановить корректную автонумерацию.

Анализ проблемы: программное создание элемента

Рассмотрим типовой пример программного кода, в котором возникает данная ошибка:


Новая_EDI_РН = Справочники.EDI_РН.СоздатьЭлемент();
Новая_EDI_РН.ДатаФормирования = ТекущаяДата();
Новая_EDI_РН.KEY = КлючЗагрузки;
Новая_EDI_РН.НомерДокумента1С = НомерРН;
Новая_EDI_РН.ДатаДокумента1С = ДатаРН;
Новая_EDI_РН.Заявка_EDI = Найденный_EDI_Заказ;
Новая_EDI_РН.Представительство = Найденный_EDI_Заказ.Представительство;
Новая_EDI_РН.Записать();

В момент вызова метода Записать() платформа автоматически пытается определить следующий свободный номер/код. Однако вместо нового максимального значения подставляются уже существующие в базе коды (например, 544, 545, 546 и т.д.), что приводит к прерыванию транзакции.

Почему сбивается механизм автонумерации

Проанализируем основные технические причины, приводящие к рассинхронизации счетчика автонумерации в платформе 1С:

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

Способ 1: Сброс кэша нумератора методом ОбновитьНумерациюОбъектов()

Основным и наиболее быстрым решением является принудительное обновление пространства номеров с помощью встроенного метода платформы ОбновитьНумерациюОбъектов(). Этот метод заставляет платформу перечитать реальные максимальные коды из таблиц СУБД и перестроить кэш нумератора.

Вызов метода без параметров выполняет обновление для всех объектов конфигурации, что при большом объеме данных создает избыточную нагрузку на базу данных:


// Не рекомендуется на высоконагруженных базах:
ОбновитьНумерациюОбъектов();

Оптимальным решением является точечное обновление нумерации конкретного справочника путем передачи в метод объекта метаданных:


// Точечное обновление нумерации для конкретного справочника:
ОбновитьНумерациюОбъектов(Метаданные.Справочники.EDI_РН);

Также метод поддерживает передачу массива объектов метаданных, если требуется сбросить нумерацию для нескольких справочников или документов одновременно.

Способ 2: Явное назначение кода перед записью объекта

Если в коде загрузки требуется гарантировать присвоение номера до выполнения события записи, вызовем метод объекта УстановитьНовыйКод():


Новая_EDI_РН = Справочники.EDI_РН.СоздатьЭлемент();
// Явно инициируем генерацию автокода до заполнения и записи
Новая_EDI_РН.УстановитьНовыйКод();

Новая_EDI_РН.ДатаФормирования = ТекущаяДата();
Новая_EDI_РН.KEY = КлючЗагрузки;
Новая_EDI_РН.НомерДокумента1С = НомерРН;
Новая_EDI_РН.ДатаДокумента1С = ДатаРН;
Новая_EDI_РН.Заявка_EDI = Найденный_EDI_Заказ;
Новая_EDI_РН.Представительство = Найденный_EDI_Заказ.Представительство;
Новая_EDI_РН.Записать();

Способ 3: Перезапуск процессов сервера 1С

Если программный сброс не дал результата, очистить зависший кэш в оперативной памяти сервера можно на уровне инфраструктуры:

  1. Завершить проблемный рабочий процесс rphost через консоль администрирования кластера серверов 1С.
  2. Выполнить перезапуск службы кластера серверов 1C:Enterprise 8.3 Server Agent.

Архитектурные рекомендации по типам кодов

При проектировании структуры справочников обратим внимание на следующие особенности:

  1. Тип кода: Механизм автонумерации платформы 1С оптимизирован для работы со строковыми типами кодов с лидирующими нулями. При использовании числового типа кода платформа лишена возможности гибко использовать префиксы, а при больших объемах данных поиск максимума может требовать больше ресурсов СУБД.
  2. Длина числового поля: Использование максимальной длины Число(38) создает повышенную нагрузку на СУБД при наложении индексных блокировок. Если справочник хранит внешние идентификаторы или технические сущности, рекомендуется использовать уникальные строковые идентификаторы UUID (GUID) либо хранить внешние ключи в отдельном реквизите, отключив контроль уникальности стандартного кода.
← На главную