Почему метод УстановитьНовыйКод() в 1С каждый раз увеличивает код без записи объекта и как это исправить?

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

В процессе разработки в среде 1С:Предприятие программисты часто сталкиваются со странным поведением автонумерации. Типичный сценарий: при создании нового элемента справочника программно вызывается метод УстановитьНовыйКод(), однако объект по каким-то причинам не записывается в базу данных. При следующем аналогичном запуске процедуры код элемента увеличивается на единицу, хотя предыдущий код так и не был сохранен. В результате в нумерации справочника образуются огромные «дыры» и пропуски.

Давайте подробно разберем, почему так происходит, как устроен внутренний механизм автонумерации платформы 1С и какими способами можно восстановить корректный порядок следования кодов.

Выясняем причину: особенности работы менеджера автонумерации

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

Для оптимизации этого процесса менеджер автонумерации кэширует последовательности номеров в оперативной памяти. Поведение этого сервиса напрямую зависит от настроек конфигурации:

  1. Режим автонумерации объектов: В свойствах конфигурации по умолчанию для этого параметра установлено значение НеОсвобождатьАвтоматически. В таком режиме при каждом вызове метода УстановитьНовыйКод() платформа резервирует очередное числовое значение в кэше сервиса.
  2. Потеря неиспользованных кодов: Если объект в памяти так и не был записан в базу (транзакция отменилась, пользователь закрыл форму без сохранения или произошел сбой), зарезервированный код безвозвратно теряется. Обратно в пул доступных номеров он уже не возвращается. При следующем запросе менеджер выдаст значение, увеличенное на единицу (+1).
  3. Использование префиксов: Когда мы передаем в метод конкретный префикс (например, Об.УстановитьНовыйКод("00")), менеджер автонумерации переключается на расчет максимального кода среди элементов, имеющих именно этот префикс. Он фиксирует в кэше новую цепочку нумерации, что временно может вернуть генерацию к ожидаемому значению, но затем проблема с резервированием повторится.

Способ 1. Принудительный сброс кэша нумерации

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

Выполнить сброс кэша для конкретного справочника можно с помощью следующего программного кода:


МетаданныеСправочника = Метаданные.Справочники.бит_ОбъектыСистемы;
ОбновитьНумерациюОбъектов(МетаданныеСправочника);

Этот метод можно вызвать во внешней обработке или выполнить в консоли кода под правами администратора. После его выполнения автонумерация вернется к нормальному состоянию «последний записанный в базе код + 1».

Способ 2. Борьба со сбитой разрядностью и «битыми» кодами

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

Перед тем как вызывать ОбновитьНумерациюОбъектов(), обязательно выполните следующие шаги:

  1. Найдите в справочнике элементы, коды которых выбиваются из общего шаблона длины или содержат нетипичные символы.
  2. Приведите длину кодов к единому стандарту (добавьте недостающие лидирующие нули).
  3. Удалите или переименуйте элементы со случайными символами в коде.
  4. Только после очистки данных примените метод обновления нумерации.

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

Способ 3. Перезапуск службы кластера серверов

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

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

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

1. Отложенное назначение кода. Не вызывайте метод УстановитьНовыйКод() сразу при создании объекта в памяти (при вызове СоздатьЭлемент()). Перенесите генерацию кода на самый последний момент — непосредственно перед вызовом метода Записать(). Либо доверьте эту операцию платформе, настроив автозаполнение кода при записи.

2. Использование стандартных событий. Вместо явного вызова метода с параметром-префиксом в теле процедур, используйте предопределенный обработчик события ПриУстановкеНовогоКода(СтандартнаяОбработка, Префикс) в модуле объекта справочника. Это позволит гибко управлять префиксами в зависимости от условий (организации, подразделения) стандартными средствами платформы.

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

← На главную