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