Когда лучше выполнять проверки при записи объекта в 1С: в событии «ПередЗаписью» или «ОбработкаПроверкиЗаполнения»?

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

При разработке конфигураций на платформе «1С:Предприятие 8» перед каждым программистом неизбежно встает вопрос: где именно реализовать проверку корректности заполнения данных? Платформа предлагает два основных инструмента в модуле объекта: обработчик ОбработкаПроверкиЗаполнения и предопределенную процедуру ПередЗаписью. На первый взгляд может показаться, что они выполняют одну и ту же задачу — не дают сохранить некорректные данные в базу. Однако их внутренняя логика, поведение в транзакции и влияние на производительность системы кардинально различаются. В этой статье мы детально разберем физический смысл этих событий, выявим ключевые различия и сформулируем правила их применения.

Суть и назначение каждого обработчика

Для начала давайте четко разграничим базовое назначение каждого из этих событий в жизненном цикле записываемого объекта:

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

Теперь рассмотрим подробнее критически важные технические различия, которые определяют выбор разработчика.

Различие №1: Транзакционность и блокировки в базе данных

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

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

Событие ПередЗаписью выполняется строго ВНУТРИ транзакции записи. Когда управление передается в этот обработчик, транзакция в базе данных уже открыта. Это означает, что любые тяжелые проверки (например, сложные запросы к базе данных, проверка взаиморасчетов или остатков) будут выполняться в режиме активной транзакции. Если проверка длится долго, она удерживает транзакционные блокировки на таблицы СУБД. Другие пользователи в этот момент не смогут провести или записать свои документы, если они затрагивают те же таблицы.

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

Различие №2: Интерактивная работа и программная запись

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

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


НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// Заполнение реквизитов...
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);

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


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

В отличие от этого, событие ПередЗаписью вызывается платформой всегда при любой записи объекта — как при интерактивной работе пользователя в форме, так и при любом программном вызове метода Записать(). Именно поэтому критически важные проверки бизнес-логики, которые ни при каких обстоятельствах не должны быть обойдены программным кодом, дублируют или полностью переносят в ПередЗаписью.

Различие №3: Механизм накопления ошибок (массив «ПроверяемыеРеквизиты»)

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

Мы можем динамически управлять этим массивом в зависимости от логики нашего приложения. Рассмотрим пример: если в документе выбран тип операции «Продажа», нам обязательно нужно проверить заполнение склада, а если «Оказание услуг» — склад проверять не нужно.


Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    // Если услуга, убираем Склад из обязательных к заполнению полей
    Если ВидОперации = Перечисления.ВидыОпераций.ОказаниеУслуг Тогда
        ПорядковыйНомер = ПроверяемыеРеквизиты.Найти("Склад");
        Если ПорядковыйНомер <> Неопределено Тогда
            ПроверяемыеРеквизиты.Удалить(ПорядковыйНомер);
        КонецЕсли;
    КонецЕсли;
    
    // Если это продажа юрлицу, то ИНН контрагента обязателен
    Если ВидОперации = Перечисления.ВидыОпераций.ПродажаЮрЛицу Тогда
        Если Не ЗначениеЗаполнено(Контрагент.ИНН) Тогда
            ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
                "У выбранного контрагента не заполнен ИНН!",
                ЭтотОбъект,
                "Контрагент",
                ,
                Отказ
            );
        КонецЕсли;
    КонецЕсли;

КонецПроцедуры

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

Различие №4: Поведение при обмене данными

Проанализируем ситуацию, когда данные загружаются в базу в рамках обмена (через РИБ, планы обмена или конвертацию данных). При загрузке данных крайне важно, чтобы проверки бизнес-логики не мешали переносу исторических или частично заполненных объектов. Для регулярной синхронизации баз по расписанию поверх существующих планов обмена используют программу для автоматического обмена данными 1С.

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


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

Если мы забудем добавить эту проверку, то при первом же обмене данными система может заблокировать загрузку пакетов из-за невыполнения какого-либо правила бизнес-логики. Что касается обработчика ОбработкаПроверкиЗаполнения, то при стандартном обмене данными запись происходит программно, поэтому платформа этот обработчик попросту игнорирует, что избавляет нас от необходимости прописывать там обход обмена данными.

Подведем итоги: шпаргалка для разработчика

Для систематизации полученных знаний проанализируем следующую сводную таблицу:

  1. Где выполняется (транзакция):
    • ОбработкаПроверкиЗаполнения: Вне транзакции (экономит ресурсы СУБД, исключает лишние блокировки).
    • ПередЗаписью: Внутри транзакции (удерживает блокировки таблиц до завершения записи).
  2. Когда вызывается автоматически:
    • ОбработкаПроверкиЗаполнения: Только при интерактивных действиях в формах.
    • ПередЗаписью: При любой записи (и интерактивной, и программной).
  3. Основное назначение:
    • ОбработкаПроверкиЗаполнения: Дружелюбная интерактивная валидация реквизитов на форме, управление составом обязательных полей.
    • ПередЗаписью: Гарантия целостности данных «в последний момент», финальные расчеты реквизитов перед непосредственной записью в базу.

Используя эти правила как стандарт разработки, мы сможем создавать не только отказоустойчивые, но и максимально производительные бизнес-приложения на платформе 1С!

← На главную