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