Как преобразовать ДанныеФормыСтруктура в обычную Структуру в 1С:Предприятии 8

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

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

Попытка выполнить прямое преобразование с помощью стандартного метода:

Поля = ДанныеФормыВЗначение(Объект, Тип("Структура"));

приводит к возникновению системной ошибки «Несоответствие типов (параметр номер '2')». Это происходит потому, что метод ДанныеФормыВЗначение предназначен исключительно для конвертации данных формы в прикладные объекты базы данных (такие как СправочникОбъект, ДокументОбъект и т. д.), но он совершенно не умеет работать с универсальной коллекцией Структура.

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

Способ 1. Статическое заполнение (если состав полей известен заранее)

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

Разберем этот метод по шагам:

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

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


// Создаем структуру с заранее известным списком ключей
НоваяСтруктура = Новый Структура("Код, Наименование, Артикул, РозничнаяЦена");

// Быстро копируем значения из данных формы в созданную структуру
ЗаполнитьЗначенияСвойств(НоваяСтруктура, Объект);

Преимущества метода: максимальное быстродействие, отсутствие накладных расходов на чтение метаданных или сериализацию, работает как на клиенте, так и на сервере.

Способ 2. Динамическое получение ключей через метод формы ПолучитьРеквизиты()

Выясним, как поступить, если состав реквизитов формы заранее неизвестен или может изменяться динамически. Если конвертируемый объект представляет собой реквизит текущей управляемой формы (например, основной реквизит Объект), мы можем задействовать контекстный метод формы ПолучитьРеквизиты(). Этот метод доступен только на сервере.

Рассмотрим подробнее алгоритм реализации:

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

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


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

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

Способ 3. Универсальный обход через XML-сериализацию (работает на клиенте и сервере)

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

Давайте разберем этот процесс по шагам:

  1. Записываем объект ДанныеФормыСтруктура во временную строку XML при помощи встроенного механизма СериализаторXDTO.ЗаписатьXML.
  2. Инициализируем объект ЧтениеXML и начинаем разбор полученной строки.
  3. При чтении элементов XML мы будем считывать имена узлов, которые в точности соответствуют именам свойств исходного объекта, и добавлять их в новую Структуру.

Посмотрим на практический пример реализации такой функции:


Функция ПреобразоватьДанныеФормыВСтруктуруСериализацией(ДанныеФормы) Экспорт

    Результат = Новый Структура;
    
    // Записываем данные формы в XML
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.УстановитьСтроку();
    СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ДанныеФормы, "FormObject", НазначениеТипаXML.Явное);
    СтрокаXML = ЗаписьXML.Закрыть();
    
    // Читаем полученную XML-строку для восстановления структуры
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СтрокаXML);
    
    // Переходим к чтению содержимого
    Пока ЧтениеXML.Прочитать() Цикл
        // Нас интересуют только открывающие теги элементов внутри объекта
        Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя <> "FormObject" Тогда
            ИмяСвойства = ЧтениеXML.Имя;
            // Добавляем ключ в структуру
            Результат.Вставить(ИмяСвойства, Неопределено);
        КонецЕсли;
    КонецЦикла;
    
    // Наполняем структуру значениями
    ЗаполнитьЗначенияСвойств(Результат, ДанныеФормы);
    
    Возврат Результат;

КонецФункции

Преимущества метода: абсолютная независимость от контекста формы. Код можно разместить в любом общем модуле и вызывать его как на стороне сервера, так и на стороне тонкого клиента (при условии доступности объектов сериализации). Для разбора сериализованных данных также можно использовать готовую функцию преобразования XML в структуру.

Способ 4. Преобразование через прикладной объект базы данных

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

Разберем по шагам, как это сделать правильно на сервере:

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

Пример кода без использования БСП (чистая платформа):


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

При использовании Библиотеки Стандартных Подсистем (БСП) данная задача упрощается до одной строки. Вы можете использовать функции копирования из общего модуля ОбщегоНазначенияКлиентСервер или ОбщегоНазначения:


// Пример использования БСП для создания копии структуры свойств
НоваяСтруктура = ОбщегоНазначения.ТаблицаЗначенийВМассивСтруктур(ТаблицаИсточеник); // Для таблиц
// Или рекурсивное копирование свойств прикладного объекта:
НоваяСтруктура = ОбщегоНазначенияКлиент.СкопироватьРекурсивно(ПрикладнойОбъект);

Подведем итоги

Выбор оптимального метода преобразования типа ДанныеФормыСтруктура в обычную Структуру зависит от вашей конкретной задачи:

← На главную