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