В каком месте кода корректнее регистрировать изменения документа вручную?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке механизмов обмена данными в среде 1С:Предприятие программисты часто сталкиваются с необходимостью ручного управления регистрацией изменений. Стандартная авторегистрация не всегда подходит под требования бизнеса, особенно когда нужно передавать данные избирательно или только при определенных условиях. В этой статье мы подробно разберем, где и как правильно использовать методы регистрации изменений, чтобы обеспечить стабильность и высокую производительность системы.

Метод ЗарегистрироватьИзменения() или свойство Получатели?

Прежде чем выбирать место в коде, проанализируем два основных способа регистрации изменений. В 1С существуют два принципиально разных подхода:

  1. Использование глобального метода ПланыОбмена.ЗарегистрироватьИзменения().
  2. Добавление узлов в коллекцию ОбменДанными.Получатели самого объекта.

Рассмотрим подробнее второй вариант. Использование коллекции Получатели в событиях ПередЗаписью или ПриЗаписи считается более «нативным» и производительным. Когда мы добавляем узел в эту коллекцию, платформа фиксирует изменение в той же самой транзакции, в которой записывается объект. Это гарантирует целостность данных: если запись объекта сорвется, регистрация тоже не произойдет. Напротив, вызов ЗарегистрироватьИзменения() инициирует отдельное обращение к таблицам регистрации, что создает дополнительную нагрузку на базу данных.

Выбор события: ПередЗаписью или ПриЗаписи?

Разберем по шагам, какое событие модуля объекта (или подписки на событие) выбрать для регистрации.

Событие ПередЗаписью

Это наиболее подходящее место для реализации сложной логики проверки. Выясним причину: именно в ПередЗаписью у нас есть доступ к старым данным объекта, хранящимся в базе (через Ссылка), и к новым данным, которые мы собираемся записать (через ЭтотОбъект). Это позволяет выполнять выборочную регистрацию.

Проанализируем пример кода для регистрации только при изменении важного реквизита:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Обязательно проверяем, не является ли запись результатом загрузки из другого обмена
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Сравниваем значение реквизита с тем, что уже записано в базе
    Если ЭтотОбъект.СуммаДокумента <> Ссылка.СуммаДокумента Тогда
        УзелОбмена = ПланыОбмена.СинхронизацияДанныхЧерезУниверсальныйФормат.НайтиПоНаименованию("Бухгалтерия");
        Если НЕ УзелОбмена.Пустая() Тогда
            // Добавляем узел в получатели - это и есть регистрация
            ЭтотОбъект.ОбменДанными.Получатели.Добавить(УзелОбмена);
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Важный нюанс: многие опасаются, что у нового документа в ПередЗаписью еще нет ссылки. Однако для механизма ОбменДанными.Получатели наличие ссылки в базе данных в этот конкретный момент не критично, так как физическая запись в системные таблицы регистрации произойдет платформой автоматически в момент завершения транзакции записи объекта.

Событие ПриЗаписи

Если нам не нужно сравнивать данные с предыдущей версией, регистрацию можно перенести в ПриЗаписи. В этом событии объект уже гарантированно получил ссылку (если он был новым), а флаг Проведен установлен в соответствии с результатом проведения. Однако помните, что на этом этапе данные в базе уже обновлены, и получить «старое» состояние через Ссылка.Реквизит не получится (оно будет равно текущему).

Регистрация в ОбработкаПроведения: почему это ошибка?

Рассмотрим ситуацию, когда разработчик решает вставить регистрацию в ОбработкаПроведения. Посмотрим на риски этого решения:

  1. Пропуск изменений: Если пользователь изменит комментарий или ответственного в документе без перепроведения (просто нажав «Записать»), событие ОбработкаПроведения не вызовется, и изменения не попадут в обмен.
  2. Отмена проведения: При пометке на удаление или отмене проведения регистрация может не сработать, если логика завязана только на модуль проведения.
  3. Зависимость от транзакции: Регистрация должна происходить при любом значимом изменении объекта, а не только при формировании движений по регистрам.

Обработка флага ОбменДанными.Загрузка

Критически важно всегда проверять свойство ОбменДанными.Загрузка = Истина. Если документ загружается из другой информационной базы, обработчики событий все равно срабатывают. Если не добавить проверку, возникнет «эффект эха»: объект пришел из базы «А», записался в базе «Б» и тут же зарегистрировался для отправки обратно в базу «А». Это приводит к бесконечным циклам обмена и неоправданному росту таблиц регистрации.

Когда использовать метод ЗарегистрироватьИзменения()?

Несмотря на преимущества коллекции Получатели, метод ПланыОбмена.ЗарегистрироватьИзменения() незаменим в следующих случаях:

Пример использования метода для массива ссылок:


МассивСсылок = Новый Массив;
// ... заполнение массива ссылками документов ...
Узел = ПланыОбмена.ГлавныйУзел();
ПланыОбмена.ЗарегистрироватьИзменения(Узел, МассивСсылок);

Итоги и рекомендации

Проанализировав различные подходы, мы можем сформулировать следующие правила:

  1. Для оперативной регистрации изменений при работе пользователя используйте событие ПередЗаписью и коллекцию ЭтотОбъект.ОбменДанными.Получатели.
  2. Всегда проверяйте ОбменДанными.Загрузка, чтобы избежать зацикливания обмена.
  3. Для групповых операций и регистрации удаления используйте метод ПланыОбмена.ЗарегистрироватьИзменения().
  4. Избегайте регистрации внутри ОбработкаПроведения, так как это не гарантирует передачу всех изменений документа.

Соблюдение этих правил обеспечит корректную работу планов обмена, минимизирует блокировки базы данных и предотвратит избыточный трафик между узлами информационной системы.

← На главную