Почему срабатывает обработчик Перед записью регистра сведений при проведении документа и как это контролировать

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

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

Разберем внутренние механизмы платформы: почему стек вызовов пуст?

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

  1. Свойство документа «Удаление движений». Если у документа установлено значение «Удалять автоматически при отмене проведения» (или «Удалять автоматически»), платформа перед началом транзакции проведения инициирует очистку старых записей. Это делается путем записи пустого набора записей по всем регистрам, где этот документ является регистратором.
  2. Механизм завершения транзакции проведения. Платформа 1С автоматически перебирает все коллекции в свойстве Движения документа после завершения процедуры ОбработкаПроведения. Если у какого-либо регистра флаг Записывать установлен в значение Истина, платформа вызывает запись этого набора.

Проанализируем ситуацию: если платформа сама вызывает метод записи в конце транзакции, в стеке вызовов не будет промежуточных процедур на встроенном языке. Это штатное поведение системы, а не ошибка.

Выясним причину двойного срабатывания обработчика

Часто разработчики сталкиваются с тем, что в ПередЗаписью набора записей выполнение заходит дважды. Рассмотрим, почему это происходит:

Первый вход: Системная очистка. Платформа проверяет наличие записей по данному регистратору и, если они потенциально могли быть (документ перепроводится), записывает пустой набор, чтобы «обнулить» состояние в базе данных.

Второй вход: Фиксация новых движений. Если в коде документа или в подписках на события произошло обращение к набору записей, платформа может автоматически взвести флаг Записывать = Истина. Даже если вы не добавили ни одной строки в набор, платформа попытается зафиксировать этот «пустой» результат в конце транзакции.

Проанализируем свойство «Записывать» и его скрытое поведение

Важно помнить об одной особенности встроенного языка: простое обращение к коллекции движений может изменить логику поведения системы. Рассмотрим пример:


// В модуле документа
Движения.МойРегистрСведений.Очистить(); 

Как только вы вызвали метод Очистить(), свойство Движения.МойРегистрСведений.Записывать автоматически устанавливается в значение Истина. Платформа запоминает, что разработчик внес изменения в коллекцию, и планирует записать ее в базу данных по завершении ОбработкаПроведения. Если вы позже в коде вручную вызываете Движения.МойРегистрСведений.Записать(), а затем платформа в конце транзакции видит флаг Записывать = Истина, она может попытаться записать его еще раз. Если к этому моменту коллекция в памяти по какой-то причине очистилась, ваши данные будут затерты пустым набором.

Как бороться с подписками на события

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

Часто в таких подписках встречается подобный код:


Для Каждого Набор Из Источник.Движения Цикл
    // Какая-то логика анализа или предварительной очистки
    Набор.Записывать = Истина;
КонецЦикла;

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

Пошаговое решение проблемы «затирания» движений

Если вы столкнулись с тем, что ваши программно созданные движения пропадают или обработчик вызывается лишний раз, выполним следующие шаги:

  1. Проверка свойства «Запись движений». Перейдите в свойства документа в конфигураторе. Найдите пункт «Запись движений при проведении». Если там стоит «Записывать всегда», платформа будет записывать все наборы, даже пустые. Рекомендуется использовать «Записывать выбранные».
  2. Контроль флага «Записывать». Если вы записываете движения вручную методом Записать(Истина) внутри ОбработкаПроведения, обязательно в конце процедуры установите флаг автоматической записи в ложь:
    
    Движения.МойРегистрСведений.Записать(Истина);
    Движения.МойРегистрСведений.Записывать = Ложь; // Отключаем повторную системную запись
    
  3. Анализ признака загрузки. В обработчике ПередЗаписью самого регистра всегда полезно проверять, не происходит ли запись в режиме обмена данными:
    
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
  4. Использование замера производительности. Если стек пуст, запустите «Замер производительности» прямо перед нажатием кнопки «Провести». После остановки посмотрите на количество вызовов функций. Даже если вызова нет в стеке, замер может показать время, затраченное на работу системных механизмов записи.

Разберем особенности для Регистров Сведений (РС)

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

Резюме

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

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

← На главную