Почему изменения данных документа в ПередЗаписьюНаСервере не сохраняются в базе данных?

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

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

Анализ проблемы: разница между Объект и ТекущийОбъект

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

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

Посмотрим на показательный пример ошибки и правильного подхода:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // ОШИБКА: Изменение реквизита формы Объект не попадет в базу данных при текущей записи!
    Объект.Комментарий = "Эта идея обречена на провал";
    
    // ПРАВИЛЬНО: Модифицируем экземпляр прикладного объекта, переданный в параметре процедуры
    ТекущийОбъект.Комментарий = "Это хорошая идея";
КонецПроцедуры

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

Особенности работы с параметром ТекущийОбъект

Разберем важные нюансы взаимодействия платформы с объектом в данном обработчике:

  1. Обратная синхронизация с формой. При успешной записи документа платформа автоматически переносит актуальные данные из ТекущийОбъект обратно в данные формы Объект. Однако если в процессе записи произойдет ошибка, будет вызвано исключение или разработчик установит Отказ = Истина, транзакция отменится, а все изменения, внесенные в ТекущийОбъект, будут безвозвратно утрачены и на клиенте не отобразятся.
  2. Производительность при работе с большими табличными частями. Прямая модификация строк в табличной части параметра ТекущийОбъект на стороне сервера выполняется значительно быстрее, чем построчная обработка коллекции Объект.<ИмяТЧ> на клиенте, так как исключаются лишние накладные расходы на передачу контекста и сериализацию данных формы.

Альтернативные варианты решения задачи

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

Вариант 1. Модификация данных на клиенте до старта записи

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


&НаСервереБезКонтекста
Функция ПолучитьРассчитанныеДанныеТЧ(ДанныеДляРасчета)
    // Выполняем выборку или расчет без контекста формы
    Возврат РезультатРасчета;
КонецФункции

&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    // Получаем необходимые значения и модифицируем Объект на клиенте
    НовыеДанные = ПолучитьРассчитанныеДанныеТЧ(Объект.Ссылка);
    // Заполняем Объект.<ИмяТЧ>
    // После этого платформа штатно сконвертирует Объект в ТекущийОбъект с новыми данными
КонецПроцедуры

Вариант 2. Перенос логики в модуль объекта через расширение

Модификация данных исключительно в модуле формы имеет существенный архитектурный недостаток: алгоритм не сработает при программной записи документа (например, при загрузке данных из внешних систем, обмене через планы обмена, выполнении регламентных заданий). Чтобы обеспечить гарантированную целостность данных, перенесем логику в модуль самого объекта конфигурации.

В расширении подключимся к событию модуля объекта с помощью аннотации &Перед:


&Перед("ПередЗаписью")
Процедура Расш_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Модифицируем табличную часть непосредственно в объекте
    Для Каждого СтрТЧ Из ЭтотОбъект.Товары Цикл
        // Выполняем заполнение реквизитов строк
    КонецЦикла;
КонецПроцедуры

Вариант 3. Передача контекста из формы в модуль объекта

Если для алгоритма в модуле объекта требуются специфические параметры, флаги или настройки, которые выбраны пользователем на форме и не хранятся в реквизитах базы данных, воспользуемся свойством ДополнительныеСвойства.

Посмотрим, как организовать передачу данных по шагам:

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

Применение правильного объекта для модификации данных исключает потерю пользовательских правок и гарантирует корректную запись документов в системе.

← На главную