При разработке сложной бизнес-логики в 1С часто возникает задача: передать временные данные, рассчитанные или отредактированные на клиенте (например, таблицу значений, вспомогательные структуры или флаги), напрямую в модуль объекта документа или справочника перед сохранением в базу данных.
Рассмотрим, почему стандартное обращение к реквизитам формы не срабатывает, как правильно использовать коллекцию ДополнительныеСвойства в управляемых формах и какие архитектурные нюансы необходимо учитывать.
Частая ошибка разработчиков — попытка обратиться к коллекции ДополнительныеСвойства напрямую через основной реквизит формы Объект:
// В коде формы:
Объект.ДополнительныеСвойства.Вставить("МояТаблица", тзДанные); // Ошибка: поле объекта не обнаружено!
Выясним причину такого поведения платформы 1С:Предприятие 8.3:
Объект имеет тип ДанныеФормыСтруктура, а не ДокументОбъект (или СправочникОбъект). Это легковесный клиентский контейнер данных, в котором содержатся только реквизиты и табличные части, объявленные в метаданных.ДополнительныеСвойства (коллекция типа Структура) принадлежит непосредственно прикладному объекту платформы (ДокументОбъект) и существует только в оперативной памяти сервера во время жизни этого экземпляра объекта.РеквизитФормыВЗначение("Объект") вне контекста сохранения формы, полученный объект не будет иметь связи с тем экземпляром, который будет реально записываться в базу.Единственной корректной точкой для внедрения произвольных данных в записываемый экземпляр объекта является серверный обработчик формы ПередЗаписьюНаСервере. В этот обработчик платформа передает параметр ТекущийОбъект, представляющий собой именно тот экземпляр объекта, который будет передан в модуль объекта.
Разберем пошагово реализацию этого механизма:
ПередЗаписьюНаСервере помещаем необходимые данные в коллекцию ДополнительныеСвойства параметра ТекущийОбъект.ПередЗаписью извлекаем переданные данные и выполняем необходимую обработку.Посмотрим на пример кода в модуле управляемой формы:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Преобразуем или берем подготовленную таблицу значений из реквизитов формы
// и передаем ее в коллекцию ДополнительныеСвойства объекта
ТекущийОбъект.ДополнительныеСвойства.Вставить("тзРаспределение", РеквизитФормыВЗначение("ТаблицаРаспределения"));
// Также можно передавать произвольные управляющие флаги
ТекущийОбъект.ДополнительныеСвойства.Вставить("ИнтерактивнаяЗаписьИзФормы", Истина);
КонецПроцедуры
Теперь рассмотрим, как прочитать эти данные в модуле объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверяем наличие переданных из формы данных
Если ДополнительныеСвойства.Свойство("тзРаспределение") Тогда
тзДанные = ДополнительныеСвойства.тзРаспределение;
// Выполняем синхронизацию и обработку данных
Для Каждого Стр Из тзДанные Цикл
// Бизнес-логика обработки
КонецЦикла;
Иначе
// Ветка для программной записи без участия формы:
// формируем или рассчитываем данные по умолчанию
тзДанные = СформироватьДанныеПоУмолчанию();
КонецЕсли;
КонецПроцедуры
Если передаваемая таблица значений содержит тысячи строк, передача ее через контекст формы увеличит нагрузку на серверные вызовы. В таких случаях разберем использование временного хранилища:
АдресВХ = ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификатор);.ТекущийОбъект.ДополнительныеСвойства передаем только строковый адрес АдресВХ.ПолучитьИзВременногоХранилища(АдресВХ).Проанализируем ключевые риски, о которых важно помнить при создании связанных документов внутри обработчика ПередЗаписью:
ПередЗаписью, ПриЗаписи и ОбработкаПроведения выполняются внутри одной транзакции базы данных. Создание десятков подчиненных документов внутри этой транзакции приводит к длительным блокировкам таблиц и потенциальным взаимным блокировкам (deadlocks).ПередЗаписью вызывается платформой не только при обычной записи, но и при проведении или отмене проведения. Всегда проверяйте параметры РежимЗаписи и РежимПроведения, чтобы не генерировать дублирующие документы.ПослеЗаписиНаСервере вне основной транзакции либо запускать через фоновое задание.