В процессе разработки в среде 1С:Предприятие программисты часто сталкиваются со странным поведением автонумерации. Типичный сценарий: при создании нового элемента справочника программно вызывается метод УстановитьНовыйКод(), однако объект по каким-то причинам не записывается в базу данных. При следующем аналогичном запуске процедуры код элемента увеличивается на единицу, хотя предыдущий код так и не был сохранен. В результате в нумерации справочника образуются огромные «дыры» и пропуски.
Давайте подробно разберем, почему так происходит, как устроен внутренний механизм автонумерации платформы 1С и какими способами можно восстановить корректный порядок следования кодов.
Начиная с версии платформы 8.1, генерацией номеров документов и кодов справочников занимается специальный внутренний сервис — менеджер автонумерации. В многопользовательской среде крайне важно обеспечить высокую скорость работы системы. Если бы платформа при каждом создании нового объекта накладывала жесткую блокировку на таблицы базы данных для поиска максимального кода, это привело бы к критическому снижению производительности и постоянным блокировкам сеансов пользователей.
Для оптимизации этого процесса менеджер автонумерации кэширует последовательности номеров в оперативной памяти. Поведение этого сервиса напрямую зависит от настроек конфигурации:
НеОсвобождатьАвтоматически. В таком режиме при каждом вызове метода УстановитьНовыйКод() платформа резервирует очередное числовое значение в кэше сервиса.Об.УстановитьНовыйКод("00")), менеджер автонумерации переключается на расчет максимального кода среди элементов, имеющих именно этот префикс. Он фиксирует в кэше новую цепочку нумерации, что временно может вернуть генерацию к ожидаемому значению, но затем проблема с резервированием повторится.Если в процессе разработки или из-за программного сбоя счетчик номеров ушел далеко вперед, мы можем принудительно очистить кэш менеджера автонумерации. Для этого в платформе предусмотрен специальный метод ОбновитьНумерациюОбъектов(). Он заставляет систему полностью стереть текущее состояние счетчиков в оперативной памяти и заново рассчитать актуальный максимум непосредственно по физически записанным в базе данных элементам.
Выполнить сброс кэша для конкретного справочника можно с помощью следующего программного кода:
МетаданныеСправочника = Метаданные.Справочники.бит_ОбъектыСистемы;
ОбновитьНумерациюОбъектов(МетаданныеСправочника);
Этот метод можно вызвать во внешней обработке или выполнить в консоли кода под правами администратора. После его выполнения автонумерация вернется к нормальному состоянию «последний записанный в базе код + 1».
Часто сброс кэша не помогает, если в самой базе данных присутствуют элементы с некорректным форматом кода. Проанализируем, почему это ломает алгоритм:
"00005" записали "5" или добавили лишний буквенный символ "00005а"), то стандартный алгоритм сравнения строк перестает работать корректно. Платформа больше не может правильно вычислить математический максимум.Перед тем как вызывать ОбновитьНумерациюОбъектов(), обязательно выполните следующие шаги:
Важное замечание: Если для справочника в конфигураторе задан числовой тип кода, то платформа будет полностью игнорировать любые строковые префиксы, передаваемые в метод УстановитьНовыйКод().
В редких случаях, особенно в распределенных базах или при высокой нагрузке на рассинхронизированные рабочие процессы, счетчик автонумерации может «застрять» в оперативной памяти сервера приложений. Если программное обновление нумерации не дало результата, решить проблему поможет перезапуск службы кластера серверов 1С:Предприятия (ragent). Это полностью очистит оперативную память рабочих процессов и обнулит все кэшированные сервером автономера.
Чтобы избежать нежелательного резервирования и пропусков кодов при программной работе с объектами, рекомендуем придерживаться следующих правил интеграции:
1. Отложенное назначение кода. Не вызывайте метод УстановитьНовыйКод() сразу при создании объекта в памяти (при вызове СоздатьЭлемент()). Перенесите генерацию кода на самый последний момент — непосредственно перед вызовом метода Записать(). Либо доверьте эту операцию платформе, настроив автозаполнение кода при записи.
2. Использование стандартных событий. Вместо явного вызова метода с параметром-префиксом в теле процедур, используйте предопределенный обработчик события ПриУстановкеНовогоКода(СтандартнаяОбработка, Префикс) в модуле объекта справочника. Это позволит гибко управлять префиксами в зависимости от условий (организации, подразделения) стандартными средствами платформы.
3. Собственный программный счетчик. Если бизнес-логика вашей задачи категорически запрещает появление любых пропусков в нумерации (например, в строгой отчетности), стандартный механизм автонумерации 1С вам не подойдет. В этом случае необходимо реализовать собственный алгоритм генерации кода: через транзакционный запрос к таблице базы данных для поиска максимального кода с явным наложением блокировки БлокировкаДанных перед непосредственным сохранением нового элемента.