При интерактивной разработке форм документов разработчики нередко сталкиваются с ситуацией: при открытии нового документа вызывается метод УстановитьНовыйНомер(), форма закрывается без сохранения или метод вызывается повторно, но при следующей генерации номер перескакивает на единицу вперед. Разберем по шагам, почему платформа 1С ведет себя именно так и как правильно организовать нумерацию документов без пропусков и блокировок.
Проанализируем внутреннее поведение платформы при выполнении метода УстановитьНовыйНомер():
УстановитьНовыйНомер() для того же объекта или пока старый объект все еще удерживается в памяти, менеджер видит, что предыдущий номер уже зарезервирован. Чтобы избежать коллизии, система выдает следующий свободный номер — на единицу больше.Рассмотрим, что произойдет, если переключить режим автонумерации на Освобождать автоматически. Номер освобождается платформой только тогда, когда объект целиком уничтожается из памяти (например, форма закрыта, а переменная очищена). Если же в рамках одной открытой формы вызвать метод повторно, номер все равно вырастет на единицу, так как объект формы удерживает выданный ранее номер.
Кроме того, данный режим считается устаревшим наследием ранних версий платформы и в высоконагруженных базах может приводить к избыточным блокировкам и снижению параллельности работы пользователей.
Стандарты разработки платформы 1С настоятельно не рекомендуют присваивать номер документу интерактивно при создании или открытии формы. Документ должен оставаться без номера до тех пор, пока пользователь явно не нажмет кнопку сохранения.
Разберем, как реализовать этот подход:
УстановитьНовыйНомер() из событий ПриСозданииНаСервере или ПриОткрытии формы. Поле номера на форме должно оставаться пустым.ПодпискаНаСобытие для метаданных с событием ПриУстановкеНовогоНомера.Посмотрим на пример обработчика в модуле документа:
Процедура ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)
// Добавляем к номеру префикс организации или узла распределенной базы
Префикс = Префикс + "ОФ_";
КонецПроцедуры
При таком подходе номер формируется ровно в момент записи. Если пользователь передумал и закрыл форму нового документа, никакого резервирования в базе не происходит, и «дырок» в нумерации не возникает.
Если в процессе тестирования или сбоев счетчик зафиксировал завышенное значение, даже после удаления ошибочных документов система может продолжать выдавать завышенные номера. Для синхронизации кэша менеджера автонумерации с фактическими данными таблиц базы используется метод глобального контекста ОбновитьНумерациюОбъектов().
Посмотрим на пример сброса счетчиков для конкретного типа документов:
// Сброс и пересчет автонумерации для одного вида документов
ОбновитьНумерациюОбъектов(Метаданные.Документы.РеализацияТоваровУслуг);
// Если вызвать метод без параметров, нумерация пересчитается для всей конфигурации
ОбновитьНумерациюОбъектов();
Рассмотрим ситуации, когда бизнес-процесс требует показать пользователю будущий номер документа еще до записи:
УстановитьНовыйНомер(). Вместо этого выполняем запрос к таблице документов, находим максимальный номер за текущий период с требуемым префиксом, прибавляем единицу и выводим полученную строку во вспомогательную надпись или реквизит формы. При этом реквизит документа Номер остается пустым вплоть до записи.