Почему пропадают данные между ПередЗаписьюНаСервере на форме и ПередЗаписью в модуле объекта?

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

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

В чем главная причина потери данных

Главная ошибка заключается в путанице между основным реквизитом формы Объект (имеющим тип ДанныеФормыСтруктураДляОбъекта) и параметром обработчика ТекущийОбъект (имеющим тип прикладного объекта базы данных, например, СправочникОбъект или ДокументОбъект).

Проанализируем сигнатуру серверного обработчика формы:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // Неправильно:
    Объект.МойРеквизит = "Тестовое значение";
    
    // Правильно:
    ТекущийОбъект.МойРеквизит = "Тестовое значение";
КонецПроцедуры

Когда мы нажимаем кнопку сохранения на форме, платформа выполняет следующие шаги:

  1. Выполняются проверки заполнения (на клиенте, на сервере формы и в модуле объекта).
  2. Платформа создает прикладной объект на основе данных формы и передает его в процедуру ПередЗаписьюНаСервере через параметр ТекущийОбъект. Транзакция записи на этом шаге еще не открыта.
  3. Если внутри этой процедуры мы присваиваем значение реквизиту формы через Объект.МойРеквизит = ..., мы меняем данные только в контексте формы. При этом созданный прикладной объект ТекущийОбъект остается без изменений.
  4. После выхода из ПередЗаписьюНаСервере платформа не переносит данные из Объект обратно в ТекущийОбъект. Она открывает транзакцию базы данных и неявно вызывает метод ТекущийОбъект.Записать(...).
  5. Управление переходит в процедуру ПередЗаписью модуля объекта. Так как в ТекущийОбъект наше поле не заполнялось, в модуле объекта оно оказывается пустым.

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

Что происходит между событиями ПередЗаписьюНаСервере и ПередЗаписью

Выясним, какие действия платформа выполняет на стыке формы и модуля объекта:

  1. Никаких промежуточных обработчиков событий формы или модуля между ними нет. Проверки заполнения (ОбработкаПроверкиЗаполненияНаСервере формы и ОбработкаПроверкиЗаполнения модуля объекта) отрабатывают строго до вызова ПередЗаписьюНаСервере.
  2. Процедура формы ПередЗаписьюНаСервере выполняется вне транзакции. Сразу после нее платформа открывает транзакцию записи и передает управление в процедуру ПередЗаписью модуля объекта. Подписки на событие ПередЗаписью срабатывают уже после завершения кода одноименной процедуры модуля объекта.

Почему в табличных частях могут неожиданно появляться данные

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

  1. Неполный состав реквизитов формы. Если форма быстрого ввода не содержит табличную часть или содержит только часть реквизитов, платформа при инициализации параметра ТекущийОбъект для существующего элемента считывает недостающие данные напрямую из базы данных. Просматривая в отладчике контекст формы Объект, мы не видим строк ТЧ, однако в ТекущийОбъект они уже присутствуют.
  2. Работа подсистем конфигурации (БСП, CRM). В формах быстрого ввода контактная информация (телефоны, email, адреса) часто вводится в простые строковые реквизиты. В процедуре ПередЗаписьюНаСервере стандартный код конфигурации преобразует эти строки и заполняет табличную часть ТекущийОбъект.КонтактнаяИнформация напрямую через вызовы общих модулей.
  3. Фильтры отладки. При пошаговом переходе по клавише F11 отладчик может сразу перескочить из модуля формы в модуль объекта, если промежуточный код выполняется в общих модулях, которые скрыты фильтрами отладки или помечены как поставляемые/служебные.

Передача параметров и дополнительных свойств из формы в объект

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

Для передачи данных в модуль объекта используем структуру ДополнительныеСвойства:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // Заполняем реквизит самого объекта
    ТекущийОбъект.Комментарий = "Записано из формы быстрого ввода";
    
    // Передаем служебный параметр в модуль объекта и подписки на события
    ТекущийОбъект.ДополнительныеСвойства.Вставить("ПропуститьПроверкуЛимитов", Истина);
КонецПроцедуры

В модуле объекта проверяем переданное значение:


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

Соблюдение этого правила гарантирует корректную запись информации: если данные должны уйти в базу или модуль объекта, модифицируем ТекущийОбъект; если требуется изменить только визуальное отображение на форме после записи, используем реквизит Объект.

← На главную