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