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