Как в управляемых формах хранить созданные, но не записанные объекты и передавать их пользователю?

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

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

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

Архитектурные ограничения платформы

Выясним причину, почему привычный для обычных форм подход не работает «из коробки»:

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

Разберем основные практические способы обхода этого ограничения без нарушения стандартов разработки.

Способ 1. Хранение объектов во временном хранилище на сервере

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

Проанализируем алгоритм работы:

  1. На сервере создаем коллекцию прикладных объектов (например, в таблице значений).
  2. Помещаем коллекцию во временное хранилище с обязательной привязкой к УникальныйИдентификатор текущей формы. Это гарантирует, что данные будут жить в памяти сервера ровно столько, сколько открыта форма.
  3. Параллельно формируем легкую таблицу (или массив структур) с полями, необходимыми пользователю для визуального выбора (наименование, артикул, цена, пометка флажком), и передаем ее в реквизиты формы.
  4. Пользователь отмечает нужные строки и нажимает кнопку записи.
  5. В серверной процедуре извлекаем исходные объекты из временного хранилища по сохраненному адресу и записываем только выбранные элементы.

Посмотрим на пример реализации серверного кода:


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

Когда пользователь подтверждает создание, на сервере восстанавливаем данные:


&НаСервере
Процедура ЗаписатьВыбранныеОбъектыНаСервере()
    ТЗОбъектов = ПолучитьИзВременногоХранилища(АдресОбъектовВПамяти);
    Если ТЗОбъектов = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Для Каждого СтрФормы Из ТаблицаФормы Цикл
        Если СтрФормы.Пометка Тогда
            СтрокаТЗ = ТЗОбъектов.Найти(СтрФормы.Индекс, "Индекс");
            Если СтрокаТЗ <> Неопределено Тогда
                Объект = СтрокаТЗ.ОбъектДанных;
                Объект.Записать();
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    // Очищаем временное хранилище после завершения работы
    УдалитьИзВременногоХранилища(АдресОбъектовВПамяти);
КонецПроцедуры

Способ 2. Сериализация объектов в XML или XDTO

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

Рассмотрим, как выгрузить объект в строку XML без создания файлов на диске:


&НаСервере
Функция СериализоватьОбъектВXML(ОбъектДанных)
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.УстановитьСтроку();
    
    // СериализаторXDTO корректно упаковывает объект со всеми табличными частями
    СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ОбъектДанных);
    
    Возврат ЗаписьXML.Закрыть();
КонецФункции

Для восстановления объекта из строки XML разберем обратную процедуру:


&НаСервере
Функция ВосстановитьОбъектИзXML(СтрокаXML)
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СтрокаXML);
    
    ОбъектДанных = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
    ЧтениеXML.Закрыть();
    
    Возврат ОбъектДанных;
КонецФункции

Полученную XML-строку можно передавать между контекстами или компактно упаковать через ХранилищеЗначения для экономии оперативной памяти.

Способ 3. Заранее назначенная ссылка для зависимых данных

Частая проблема при создании объектов без записи — зависимые данные. Например, позиция номенклатуры еще не сохранена, но для нее уже требуется заполнить единицы измерения или характеристики, подчиненные этому элементу.

Посмотрим, как платформа позволяет обойти эту проблему:


&НаСервере
Процедура ПодготовитьОбъектСНовойСсылкой()
    НоваяНоменклатура = Справочники.Номенклатура.СоздатьЭлемент();
    
    // Генерируем уникальный идентификатор и будущую ссылку
    БудущаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор);
    
    // Назначаем ссылку незаписанному объекту
    НоваяНоменклатура.УстановитьСсылкуНового(БудущаяСсылка);
    НоваяНоменклатура.Наименование = "Сложный товар";
    
    // Теперь эту ссылку можно использовать в подчиненных структурах и реквизитах
КонецПроцедуры

Способ 4. Интерактивное открытие формы нового объекта с данными

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

  1. Через параметры заполнения формы:

    При вызове ОткрытьФорму() на клиенте передаем структуру ЗначенияЗаполнения:

    
    &НаКлиенте
    Процедура ОткрытьФормуНовогоЭлемента()
        ПараметрыЗаполнения = Новый Структура;
        ПараметрыЗаполнения.Вставить("Наименование", "Тестовый элемент");
        ПараметрыЗаполнения.Вставить("Артикул", "ТЕСТ-001");
        
        ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
        ОткрытьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыФормы, ЭтаФорма);
    КонецПроцедуры
    

    В этом случае платформа сама создаст новый элемент, вызовет событие ОбработкаЗаполнения в модуле объекта и покажет готовую форму пользователю. Запись произойдет только тогда, когда пользователь нажмет кнопку «Записать и закрыть».

  2. Через преобразование данных формы на сервере:

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

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

← На главную