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