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

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

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

Режим загрузки данных (DataExchange.Load)

Первое, на что необходимо обратить внимание при программной записи объекта — это свойство ОбменДанными.Загрузка. Рассмотрим, как это влияет на поведение системы. Когда мы устанавливаем этот флаг в значение Истина, платформа отключает большинство прикладных проверок, включая контроль уникальности номеров и кодов. Это сделано для того, чтобы при переносе данных из других систем (например, через конвертацию данных или при распределенных информационных базах) не возникало конфликтов с уже существующими правилами логики текущей базы.

Если в вашем коде встречается подобная конструкция, контроль уникальности работать не будет:


НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Номер = "000001"; // Номер, который уже есть в базе
НовыйДокумент.ОбменДанными.Загрузка = Истина; 
НовыйДокумент.Записать(); // Ошибки не будет, дубль создастся

Проанализируем ситуацию: если вы уверены, что ОбменДанными.Загрузка установлена в Ложь (или не устанавливалась вовсе, так как по умолчанию она ложна), а дубли всё равно создаются, перейдем к следующим пунктам.

Влияние объекта «Нумератор»

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

Выясним причину возможного сбоя: если вы включили контроль уникальности в самом документе, но забыли проверить аналогичную галочку в связанном нумераторе, система позволит записывать одинаковые номера. Проверьте дерево метаданных: ветка Общие -> Нумераторы.

Особенности транзакционной записи

Контроль уникальности в 1С — это не мгновенная проверка при присвоении строки свойству Номер. Это механизм, который срабатывает непосредственно в момент попытки зафиксировать изменения в таблицах СУБД. Рассмотрим ситуацию, когда создание документа происходит внутри сложной транзакции.

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

Момент присвоения номера в коде

Посмотрим на последовательность событий при записи объекта. Платформа выполняет проверку уникальности на определенном этапе. Если мы программно меняем номер в обработчике события ПередЗаписью, мы можем «обмануть» стандартный алгоритм. Проанализируем пример:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Платформа уже могла подготовить проверку для старого номера
    // Но здесь мы принудительно меняем его на дублирующийся
    ЭтотОбъект.Номер = "УЖЕ_ЕСТЬ_В_БАЗЕ";
КонецПроцедуры

В ряде версий платформы ручное переопределение номера «в последний момент» позволяет обойти стандартный фильтр уникальности, так как внутренняя системная проверка может не инициироваться повторно после изменения значения в коде обработчика.

Скрытые символы и визуальная идентичность

Часто разработчики утверждают, что номера абсолютно одинаковы, и даже сравнение в коде Док1.Номер = Док2.Номер выдает Истина. Однако это может быть иллюзией. Разберем подробнее:

  1. Невидимые символы: В конце или начале номера может стоять неразрывный пробел Символ(160) или символы табуляции. При сравнении строк 1С может игнорировать некоторые различия в зависимости от настроек сопоставления (collation) базы данных, но для уникального индекса SQL — это разные строки.
  2. Разная раскладка: Латинская «A» и кириллическая «А» выглядят одинаково, но имеют разные коды.

Чтобы исключить эту причину, попробуем использовать функцию СтрДлина() для обоих номеров или вывести их коды символов. Если длины совпадают, стоит проверить базу через консоль запросов, сравнив результаты выборки по этим номерам.

Ошибки кэширования нумерации в 8.3

Начиная с версии платформы 8.3, для ускорения работы был введен механизм кэширования номеров на стороне сервера приложений. Это означает, что сервер «бронирует» диапазон номеров. Выясним, как это влияет на уникальность: при интенсивной многопользовательской работе или специфических ошибках кэша система может допустить коллизию. Хотя это считается критической ошибкой платформы, такие случаи фиксировались в ранних релизах 8.3.10-8.3.12. Помогает обычно перезапуск службы сервера 1С или изменение режима автонумерации в свойствах конфигурации на «Не использовать» с последующим возвратом.

Сбой индексов базы данных

Если все настройки верны, а дубли продолжают появляться, проблема может лежать на уровне СУБД (MS SQL, PostgreSQL). Уникальность номера обеспечивается уникальным индексом в таблице документов. Если индекс поврежден (дефрагментирован или «слетел»), СУБД перестает выбрасывать ошибку Duplicate Key.

Для решения этой проблемы выполним следующие шаги:

  1. Запустим конфигуратор.
  2. Перейдем в меню Администрирование -> Тестирование и исправление....
  3. Выберем пункт «Переиндексация таблиц информационной базы».
  4. Нажмем «Выполнить».

Это принудительно пересоберет все индексы и восстановит механизм контроля на физическом уровне.

Использование метода УстановитьНовыйНомер()

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


НовыйДок = Документы.ПриходныйКассовыйОрдер.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДата();
НовыйДок.УстановитьНовыйНомер(); // Платформа сама найдет свободный номер
НовыйДок.Записать();

Если же вы сначала вызываете УстановитьНовыйНомер(), а потом вручную меняете его на существующий, контроль уникальности может сработать некорректно в зависимости от того, в какой момент происходит вызов Записать(). Помните: ручное вмешательство в автонумерацию — основная причина возникновения дублей.

Подводя итог, можно сказать, что «чудес» не бывает. Если контроль уникальности стоит, а дубль записывается, значит, либо включен режим загрузки данных, либо настройки делегированы нумератору, либо имеет место технический сбой индексов или кэша. Тщательная проверка этих пунктов позволит восстановить целостность данных в вашей системе.

← На главную