Как передать таблицу значений или переменную из формы в модуль объекта при записи

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

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

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

Причина ошибки при обращении к ДополнительныеСвойства через реквизит Объект

Частая ошибка разработчиков — попытка обратиться к коллекции ДополнительныеСвойства напрямую через основной реквизит формы Объект:


// В коде формы:
Объект.ДополнительныеСвойства.Вставить("МояТаблица", тзДанные); // Ошибка: поле объекта не обнаружено!

Выясним причину такого поведения платформы 1С:Предприятие 8.3:

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

Основное решение: передача данных в обработчике ПередЗаписьюНаСервере

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

Разберем пошагово реализацию этого механизма:

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

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


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

Теперь рассмотрим, как прочитать эти данные в модуле объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Проверяем наличие переданных из формы данных
    Если ДополнительныеСвойства.Свойство("тзРаспределение") Тогда
        тзДанные = ДополнительныеСвойства.тзРаспределение;
        
        // Выполняем синхронизацию и обработку данных
        Для Каждого Стр Из тзДанные Цикл
            // Бизнес-логика обработки
        КонецЦикла;
    Иначе
        // Ветка для программной записи без участия формы:
        // формируем или рассчитываем данные по умолчанию
        тзДанные = СформироватьДанныеПоУмолчанию();
    КонецЕсли;
    
КонецПроцедуры

Оптимизация при передаче больших объемов данных

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

  1. На сервере формы помещаем таблицу во временное хранилище: АдресВХ = ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификатор);.
  2. В ТекущийОбъект.ДополнительныеСвойства передаем только строковый адрес АдресВХ.
  3. В модуле объекта извлекаем таблицу через ПолучитьИзВременногоХранилища(АдресВХ).

Важные архитектурные предостережения

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

  1. Неявная транзакция: Обработчики ПередЗаписью, ПриЗаписи и ОбработкаПроведения выполняются внутри одной транзакции базы данных. Создание десятков подчиненных документов внутри этой транзакции приводит к длительным блокировкам таблиц и потенциальным взаимным блокировкам (deadlocks).
  2. Повторные вызовы: Процедура ПередЗаписью вызывается платформой не только при обычной записи, но и при проведении или отмене проведения. Всегда проверяйте параметры РежимЗаписи и РежимПроведения, чтобы не генерировать дублирующие документы.
  3. Разделение логики: Если операция создания зависимых документов ресурсоемкая, рекомендуется выносить её выполнение в обработчик ПослеЗаписиНаСервере вне основной транзакции либо запускать через фоновое задание.
← На главную