Почему ЗаполнитьЗначенияСвойств() не передает данные в XDTO-объектах веб-сервиса и как это исправить?

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

При разработке интеграций через веб-сервисы (SOAP) в среде 1С:Предприятие программисты часто сталкиваются с неочевидным поведением объектов XDTO. Типичная ситуация: вы создаете структуру данных на основе XDTO-пакета, заполняете ее из таблицы значений или выборки запроса с помощью стандартного метода ЗаполнитьЗначенияСвойств(), проверяете объект в отладчике — он заполнен. Однако на стороне системы-приемника или даже при анализе XML-пакета выясняется, что поля приходят пустыми. При этом переход на «ручное» присваивание каждого поля через точку (явный маппинг) мгновенно решает проблему.

В этой статье мы подробно разберем, почему универсальный механизм 1С дает сбой в контексте XDTO, проанализируем внутреннее устройство сериализации и выработаем надежные стратегии заполнения данных для веб-сервисов.

Разберем причину проблемы: состояние «Установлено» (IsSet)

Главное отличие объекта XDTO от обычной структуры или прикладного объекта 1С заключается в том, что каждое его свойство обладает не только значением, но и специальным внутренним состоянием — признаком «Установлено». Механизм XML-сериализации 1С, который формирует SOAP-ответ, ориентируется именно на этот флаг.

Проанализируем ситуацию: когда мы выполняем прямое присваивание вида ОбъектXDTO.Поле = Значение, платформа гарантированно переключает состояние свойства в «Установлено». Если же используется метод ЗаполнитьЗначенияСвойств(), в некоторых версиях платформы или при определенных настройках XSD-схемы (например, при использовании типов, отличных от стандартных строк xs:string), данные записываются в память объекта, но флаг для сериализатора не взводится. В итоге при формировании XML-тега система считает, что значение не было задано, и либо игнорирует узел, либо передает его пустым.

Проанализируем влияние типизации и фасетов

XDTO-пакеты очень чувствительны к типам данных. Даже если в пакете указан тип string, это может быть не примитивный xs:string, а производный тип с ограничениями (фасетами). Рассмотрим основные нюансы:

  1. Отсутствие неявного приведения: Метод ЗаполнитьЗначенияСвойств() работает как простое копирование. Если в колонке Таблицы Значений (ТЗ) лежит число, а XDTO ожидает строку, метод может не выполнить преобразование так, как этого ожидает схема XSD.
  2. Namespace (Пространства имен): Объекты XDTO жестко привязаны к пространствам имен. Если структура ТЗ не совпадает до символа с именами свойств в схеме (включая регистр и иногда префиксы), универсальный метод может пропустить поля.
  3. Атрибут nillable: Если в схеме указано nillable="true", пустое значение из 1С может превратиться в xsi:nil="true", что приемник интерпретирует как NULL, а не как пустую строку. Явное присвоение "" помогает 1С четко понять намерение разработчика.

Рассмотрим правильный подход к наполнению списков (Composition)

Часто ошибка кроется в последовательности действий при работе со списками объектов XDTO. Посмотрим на пример кода, который может работать нестабильно:


ТаблицаЗначенийТип = ФабрикаXDTO.Тип("http://mysite.ru", "ValueTable");
СтрокаТЗТип = ФабрикаXDTO.Тип("http://mysite.ru", "TableString");

ВыхТаблица = ФабрикаXDTO.Создать(ТаблицаЗначенийТип);

Для каждого Стр из ТзДляВыгрузки Цикл
    // ОШИБКА: Создание объекта в отрыве от родительского списка
    СтрокаXDTO = ФабрикаXDTO.Создать(СтрокаТЗТип);
    ЗаполнитьЗначенияСвойств(СтрокаXDTO, Стр);
    ВыхТаблица.Composition.Добавить(СтрокаXDTO);
КонецЦикла;

Выясним, как сделать это правильно. Для стабильной сериализации рекомендуется сначала добавлять пустой элемент в список, получать на него ссылку и уже затем заполнять свойства этого «живого» объекта, который уже находится в контексте родителя:


Для каждого Стр из ТзДляВыгрузки Цикл
    // ПРАВИЛЬНО: Добавляем элемент и получаем ссылку
    НоваяСтрокаXDTO = ВыхТаблица.Composition.Добавить();
    // Теперь заполняем объект, который уже является частью коллекции
    ЗаполнитьЗначенияСвойств(НоваяСтрокаXDTO, Стр);
    
    // Если ЗаполнитьЗначенияСвойств все же не срабатывает, используем явный маппинг:
    // НоваяСтрокаXDTO.Поле1 = Стр.Поле1;
КонецЦикла;

Решение №1: Использование явного маппинга

Хотя явное присваивание кажется более трудоемким, для веб-сервисов это считается лучшей практикой. Проанализируем преимущества этого метода:

Пример надежного маппинга:


Для каждого Стр из ТзДляВыгрузки Цикл
    НоваяСтрока = ВыхТаблица.Composition.Добавить();
    НоваяСтрока.ID = Строка(Стр.ID);
    НоваяСтрока.Name = СокрЛП(Стр.Имя);
    НоваяСтрока.Amount = Стр.Сумма;
КонецЦикла;

Решение №2: Написание собственной процедуры заполнения

Если полей в таблице очень много и они постоянно меняются, можно реализовать обход свойств программно, используя метод Установить(). Это позволит обойти ограничения ЗаполнитьЗначенияСвойств(), сохраняя при этом универсальность.

Разберем пример такой процедуры:


Процедура ЗаполнитьXDTOИзСтруктуры(ОбъектXDTO, Данные)
    ТипОбъекта = ОбъектXDTO.Тип();
    Для каждого Свойство Из ТипОбъекта.Свойства Цикл
        ИмяПоля = Свойство.Имя;
        Если Данные.Свойства().Найти(ИмяПоля) <> Неопределено Тогда
            // Используем метод Установить(), который принудительно взводит флаг IsSet
            ОбъектXDTO.Установить(ИмяПоля, Данные[ИмяПоля]);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Эта процедура проходит по описанию свойств самого XDTO-пакета и ищет соответствующие данные в источнике (например, в строке ТЗ). Использование метода Установить() является ключевым моментом, так как он работает на более низком уровне взаимодействия с фабрикой XDTO.

Выясним, когда стоит использовать ЗаполнитьЗначенияСвойств()

Означает ли вышесказанное, что ЗаполнитьЗначенияСвойств() вообще нельзя использовать? Нет. Посмотрим, в каких случаях этот метод будет работать корректно:

Однако в интеграционных задачах, где важна точность каждого байта в XML-пакете, лучше придерживаться стратегии явного определения данных. Это избавит вас от трудноуловимых багов, когда данные «вроде бы есть» в отладке, но «почему-то нет» в сети.

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

Мы проанализировали проблему отсутствия данных при передаче через веб-сервис и пришли к следующим выводам:

  1. Метод ЗаполнитьЗначенияСвойств() может не активировать внутренний механизм пометки свойства XDTO как заполненного (флаг IsSet).
  2. Для списков (коллекций) XDTO критически важно сначала добавлять элемент в родительский объект методом Добавить(), а затем заполнять его свойства.
  3. Явный маппинг полей через точку — самый надежный способ передачи данных, исключающий ошибки типизации и пустые узлы в XML.
  4. При необходимости автоматизации заполнения следует использовать метод Установить() объекта XDTO в цикле по свойствам типа.

Соблюдение этих правил позволит создавать стабильные и производительные интеграционные решения на платформе 1С, работающие корректно с любыми внешними системами.

← На главную