В процессе разработки, интеграции или переноса данных в системе «1С:Предприятие» программисты нередко сталкиваются с ситуацией, когда необходимо обойти стандартные жесткие ограничения платформы. Одним из таких ограничений является контроль уникальности кодов справочников. Когда в свойствах объекта конфигурации включены свойства «Автонумерация» и «Контроль уникальности», стандартная интерактивная или программная запись элемента с уже существующим в базе кодом вызовет ошибку СУБД, и транзакция будет отменена.
Однако в платформе заложен штатный механизм, позволяющий обойти это ограничение для административных и интеграционных целей. Разберем подробно, как реализовать эту задачу программно, как работает данный механизм под капотом платформы, а также проанализируем потенциальные опасности появления дублирующихся кодов в информационной базе.
Для того чтобы заставить платформу «закрыть глаза» на контроль уникальности кодов (а также номеров документов), необходимо использовать специальное свойство объекта — ОбменДанными.Загрузка. Установив его значение в Истина непосредственно перед вызовом метода Записать(), мы отключаем стандартные проверки.
Рассмотрим практический пример кода, с помощью которого мы можем создать элемент справочника с заведомо дублирующимся кодом:
// Создаем новый элемент справочника Номенклатура
НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
// Заполняем обязательные реквизиты
НовыйЭлемент.Наименование = "Дубликат товара";
// Явно указываем код, который уже существует в системе
НовыйЭлемент.Код = "000000001";
// Включаем режим загрузки данных для обхода проверок
НовыйЭлемент.ОбменДанными.Загрузка = Истина;
// Записываем элемент без стандартных проверок платформы
Попытка
НовыйЭлемент.Записать();
Сообщить("Элемент успешно записан с дублирующимся кодом!");
Исключение
Сообщить("Не удалось записать элемент: " + ОписаниеОшибки());
КонецПопытки;
Давайте разберем по шагам, что происходит в системе при выполнении этого кода и почему данный способ срабатывает.
Когда мы присваиваем свойству ОбменДанными.Загрузка значение Истина, платформа переходит в специальный режим записи «как есть». Этот режим изначально проектировался для механизмов синхронизации (например, при обмене данными через XML или планы обмена), чтобы принимающая база могла беспрепятственно записать любые данные, пришедшие из источника.
В этом режиме происходят следующие важные изменения в поведении платформы:
Записать() разработчик программно не присвоил код, элемент запишется с абсолютно пустым кодом. Повторный запуск такого кода приведет к появлению множества элементов с пустыми кодами, что тоже является дублированием.Существует распространенное заблуждение среди начинающих разработчиков, что свойство ОбменДанными.Загрузка = Истина полностью отменяет выполнение любого кода в модуле объекта. Это не так. Платформа не отменяет вызов процедур-обработчиков событий, таких как ПередЗаписью, ПриЗаписи, а также зарегистрированных подписок на эти события.
Предотвращение проверок кастомной бизнес-логики происходит исключительно благодаря соблюдению стандартов разработки фирмы «1С» (в частности, стандартов Библиотеки Стандартных Подсистем — БСП). Согласно этим стандартам, любой обработчик событий в модуле объекта или подписке должен начинаться со следующей конструкции:
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Далее следует основная бизнес-логика и проверки
...
КонецПроцедуры
Если разработчик конфигурации (или автор некачественной доработки) забыл написать эту проверку в начале процедуры модуля конкретного справочника, то даже при установленном флаге Загрузка = Истина весь кастомный код проверки выполнится. В этом случае транзакция записи может быть заблокирована, если внутри обработчика прописаны собственные жесткие алгоритмы контроля.
Помимо прямого использования свойства ОбменДанными.Загрузка = Истина в обработках, дублирующиеся коды могут появиться в системе следующими путями:
ОбменДанными.Загрузка = Истина, в результате чего в базе вполне законно появляются два разных элемента с идентичными кодами.Программно обойти платформенные ограничения несложно, однако создание дублирующихся кодов — это серьезная мина замедленного действия для стабильной работы всей информационной системы. Проанализируем основные проблемы, с которыми обязательно столкнутся пользователи и разработчики в процессе эксплуатации такой базы:
НайтиПоКоду() всегда будет возвращать ссылку только на один элемент справочника (тот, который окажется первым в индексе СУБД). Найти второй элемент с точно таким же кодом этим методом станет невозможно. Для его получения программисту придется переписывать алгоритмы на использование прямых запросов СУБД или выполнять поиск по внутреннему уникальному идентификатору (UUID/GUID).Подведем итог: Использовать свойство ОбменДанными.Загрузка = Истина для создания дублирующихся кодов можно, и в ряде специфических задач (например, при сложной миграции исторических данных) это действительно необходимо. Однако всегда помните о последствиях и закладывайте в свои алгоритмы механизмы автоматического исправления кодов или поиска дублей, чтобы избежать серьезных сбоев при дальнейшей эксплуатации базы данных.