Как правильно реализовать нумератор объектов в 1С: использовать справочник или регистр сведений?

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

При проектировании прикладных решений на платформе «1С:Предприятие» разработчики часто сталкиваются с задачей генерации уникальных человекочитаемых идентификаторов. Это могут быть номера договоров, артикулы товаров, номера дисконтных карт, штрихкоды или коды пакетов обмена. Использовать системный уникальный идентификатор (GUID) в таких случаях невозможно, так как пользователям необходим понятный буквенно-цифровой код (например, ОРГ-000045), состоящий из префикса и последовательно увеличивающегося счетчика.

В этой статье мы подробно проанализируем два основных архитектурных подхода к созданию собственного нумератора: использование стандартной автонумерации справочника и создание кастомного механизма на базе регистра сведений. Мы рассмотрим сильные и слабые стороны каждого варианта, а также разберем вопросы блокировок СУБД в высоконагруженных системах.

Вариант 1. Использование встроенной автонумерации справочника

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

Рассмотрим по шагам, как настроить такой справочник:

  1. Установите длину наименования равной 0 (наименование нам не понадобится).
  2. Задайте тип кода Строка и определите необходимую длину (например, 10 или 15 символов).
  3. Включите свойство Автонумерация и выберите тип контроля уникальности.

При таком подходе для получения нового номера достаточно программно создать элемент справочника, записать его и считать полученный код:


НовыйЭлемент = Справочники.НумераторОбъектов.СоздатьЭлемент();
НовыйЭлемент.УстановитьНовыйКод("ПРФ-"); // Установка префикса
НовыйЭлемент.Записать();
ПолученныйНомер = НовыйЭлемент.Код;

Преимущества использования справочника:

Недостатки и подводные камни:

Вариант 2. Использование регистра сведений («Максимум + 1»)

Второй популярный вариант — создание собственного счетчика в непериодическом регистре сведений. В этом случае мы храним текущее состояние счетчика в разрезе префиксов. Структура регистра (например, РегистрСведений.СобственныеНумераторы) выглядит следующим образом:

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

Проанализируем проблему конкурентного доступа. В многопользовательской среде два сеанса могут одновременно прочитать одно и то же максимальное значение из регистра. В результате оба прибавят единицу, получат одинаковые номера и попытаются записать их. Это приведет либо к дублированию номеров, либо к ошибке транзакции.

Чтобы избежать этой проблемы в управляемом режиме блокировок, необходимо использовать механизм управляемых блокировок. Мы должны принудительно заблокировать запись по конкретному префиксу перед чтением. Выстроив обращения пользователей в строгую очередь, мы гарантируем уникальность номеров.

Рассмотрим пример кода для получения номера через регистр сведений:


Функция ПолучитьСледующийНомер(ИмяПрефикса, ДлинаЧисла) Экспорт
    
    НачатьТранзакцию();
    Попытка
        // 1. Установка управляемой блокировки на конкретный префикс
        Блокировка = Новый БлокировкаДанных;
        ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СобственныеНумераторы");
        ЭлементБлокировки.УстановитьЗначение("Префикс", ИмяПрефикса);
        ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
        Блокировка.Заблокировать();
        
        // 2. Чтение текущего значения счетчика
        Отбор = Новый Структура("Префикс", ИмяПрефикса);
        ЗначениеСчетчика = 0;
        
        Выборка = РегистрыСведений.СобственныеНумераторы.Выбрать(Отбор);
        Если Выборка.Следующий() Тогда
            ЗначениеСчетчика = Выборка.ТекущееЗначение;
        КонецЕсли;
        
        // Инкремент счетчика
        НовоеЗначение = ЗначениеСчетчика + 1;
        
        // 3. Запись обновленного значения в регистр
        МенеджерЗаписи = РегистрыСведений.СобственныеНумераторы.СоздатьМенеджерЗаписи();
        МенеджерЗаписи.Префикс = ИмяПрефикса;
        МенеджерЗаписи.ТекущееЗначение = НовоеЗначение;
        МенеджерЗаписи.Записать(Истина);
        
        ЗафиксироватьТранзакцию();
        
        // 4. Форматирование номера (добавление префикса и лидирующих нулей)
        ФорматированныйНомер = ФорматироватьНомер(ИмяПрефикса, НовоеЗначение, ДлинаЧисла);
        Возврат ФорматированныйНомер;
        
    Исключение
        ОтменитьТранзакцию();
        ВызватьИсключение "Не удалось сгенерировать номер: " + ОписаниеОшибки();
    КонецПопытки;
    
КонецФункции

Функция ФорматироватьНомер(Префикс, ЧислоНомера, ОбщаяДлина)
    СтрокаЧисла = Формат(ЧислоНомера, "ЧГ=0");
    ДлинаПрефикса = СтрДлина(Префикс);
    ДлинаНулей = ОбщаяДлина - ДлинаПрефикса - СтрДлина(СтрокаЧисла);
    
    ЛидирующиеНули = "";
    Для Счетчик = 1 По ДлинаНулей Цикл
        ЛидирующиеНули = ЛидирующиеНули + "0";
    КонецЦикла;
    
    Возврат Префикс + ЛидирующиеНули + СтрокаЧисла;
КонецФункции

Преимущества использования регистра сведений:

Недостатки:

Резюме: что же выбрать?

Выбор конкретного технического решения зависит от бизнес-требований к вашей системе:

  1. Если вам важна простота разработки, а пропуски в номерах не являются критической ошибкой для бизнеса — смело используйте стандартный справочник с нулевой длиной наименования. Платформа 1С возьмет на себя всю рутину по генерации кодов.
  2. Если бизнес-процессы требуют строгой непрерывной нумерации без пропусков или система проектируется под высокую нагрузку, где важна оптимизация размера таблиц СУБД — используйте решение на базе регистра сведений с управляемыми блокировками.
← На главную