Как исправить ошибку "Поле недоступно для записи" при работе с XDTO-объектами в 1С

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

При интеграции с внешними системами через веб-сервисы (SOAP) часто возникает задача создания и заполнения сложных XDTO-объектов. В процессе можно столкнуться с ошибкой «Поле объекта недоступно для записи», даже если, на первый взгляд, код выглядит корректно. Разберем на примере, почему возникает эта ошибка и как правильно работать с такими объектами.

Автор столкнулся с проблемой при попытке заполнить свойство MATERIAL у созданного XDTO-объекта. Код завершался ошибкой на строке ОбъектXDTO.MATERIAL = MATERIAL;. Проанализируем ситуацию и найдем правильное решение.

Анализ проблемы: почему поле "недоступно для записи"?

Ключ к пониманию ошибки лежит в структуре данных, которая описывается XSD-схемой веб-сервиса. В схеме для каждого элемента можно указать атрибуты minOccurs (минимальное количество вхождений) и maxOccurs (максимальное количество вхождений).

Если для элемента, такого как MATERIAL, атрибут maxOccurs установлен в значение больше 1 (например, maxOccurs="100" или maxOccurs="unbounded"), платформа 1С интерпретирует это свойство не как одиночный объект, а как список или коллекцию. В терминах 1С это будет объект типа СписокXDTO (XDTOList).

Именно здесь и кроется главная особенность:

Свойство, содержащее коллекцию (СписокXDTO), является свойством только для чтения.

Это означает, что вы не можете напрямую присвоить ему новое значение (новый объект или массив). Платформа автоматически создает пустой объект СписокXDTO в этом свойстве в момент создания родительского объекта. Ваша задача — не заменить этот список, а добавить элементы в него.

Таким образом, ошибка «Поле недоступно для записи» возникает из-за попытки перезаписать системно созданную коллекцию, что запрещено платформой.

Пошаговое решение: правильное заполнение списочных свойств

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

Шаг 1. Инициализация и получение типов

Сначала, как и в исходном коде, мы подключаемся к веб-сервису и получаем фабрику XDTO.


// Подключение к веб-сервису
мОпределения = Новый WSОпределения(Узел.URL + "?wsdl", Узел.Пользователь, Узел.Пароль);
Прокси = Новый WSПрокси(мОпределения, "urn:sap-com:document:sap:soap:functions:mc-style", "MaterialMasterService", "MaterialMasterPort");
Прокси.Пользователь = Узел.Пользователь;
Прокси.Пароль = Узел.Пароль;

// Получаем фабрику XDTO из прокси
Фабрика = Прокси.ФабрикаXDTO;

Далее нужно правильно получить типы для родительского объекта и для элемента, который мы будем добавлять в список. Автор в одном из сообщений пришел к верному способу получения типа для вложенного элемента:

  1. Получаем тип родительского объекта (например, DT_MaterialList).
  2. Через его свойства получаем тип для элемента списка (MATERIAL).

Это надежный способ, так как он не зависит от ручного указания полного имени типа с пространством имен.


// 1. Получаем тип родительского объекта (например, тип параметра веб-метода)
// Имя типа нужно смотреть в WSDL или в отладчике
НоменклатураТип = Фабрика.Тип("urn:sap-com:document:sap:soap:functions:mc-style", "DT_MaterialList");

// 2. Получаем тип элемента, который будет находиться в списке MATERIAL
// Обращаемся к свойству родительского типа и берем его тип
МатериалТип = НоменклатураТип.Свойства.Получить("MATERIAL").Тип;

Важно: НоменклатураТип.Свойства.Получить("MATERIAL").Тип вернет тип элемента коллекции, а не тип самой коллекции. Это именно то, что нам нужно для создания нового материала.

Шаг 2. Создание и заполнение объектов

Теперь создаем экземпляры родительского и дочернего объектов с помощью метода Фабрика.Создать().


// Создаем родительский объект XDTO
ОбъектXDTO = Фабрика.Создать(НоменклатураТип);

// Создаем объект для добавления в список
МатериалXDTO = Фабрика.Создать(МатериалТип);

Заполняем свойства созданного объекта МатериалXDTO, как и планировалось.


// Заполняем поля простого типа в родительском объекте, если они есть
ОбъектXDTO.INTCODE = 13;

// Заполняем поля дочернего объекта
МатериалXDTO.MATNR = Выборка.Артикул + "NF";
МатериалXDTO.DELIND = 0;
МатериалXDTO.MATTXT = Выборка.Наименование;
МатериалXDTO.BASEUOM = Выборка.БазоваяЕдиницаИзмерения;
МатериалXDTO.ARTIC = Выборка.Артикул + "NF";
МатериалXDTO.PACMASS = Выборка.Вес;
МатериалXDTO.NESTAM = Выборка.ЕдиницаИзмеренияМестКоэффициент;
МатериалXDTO.SHLIFE = Выборка.СрокГодности;

Шаг 3. Добавление элемента в список

Это ключевой момент. Вместо неверной операции присваивания ОбъектXDTO.MATERIAL = МатериалXDTO; используем правильный подход: обращаемся к свойству-коллекции MATERIAL и вызываем у него метод Добавить().


// Правильный способ: добавляем созданный и заполненный объект в коллекцию
ОбъектXDTO.MATERIAL.Добавить(МатериалXDTO);

Если по логике нужно передать несколько материалов, можно организовать цикл и добавлять в него столько объектов, сколько требуется. Каждый раз нужно будет создавать новый экземпляр МатериалXDTO.

Теперь объект ОбъектXDTO полностью сформирован и готов для передачи в качестве параметра метода веб-сервиса.

Эффективная отладка XDTO-объектов

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

Для этого используется объект ЗаписьXML.


// Создаем объект для записи XML в строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("UTF-8"); // Указываем кодировку

// Устанавливаем красивый вывод с отступами для удобства чтения
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.Форматировать = Истина;

// Сериализуем наш XDTO-объект в XML
Фабрика.ЗаписатьXML(ЗаписьXML, ОбъектXDTO, "ИмяКорневогоЭлемента"); // Имя корневого элемента можно посмотреть в схеме

// Получаем результат в виде строки
XMLСтрока = ЗаписьXML.Закрыть();

// Теперь можно посмотреть переменную XMLСтрока в отладчике или вывести в Сообщения
Сообщить(XMLСтрока);

Этот метод отладки сразу покажет, является ли свойство списком (в XML будут повторяющиеся теги), корректно ли заполнены все поля и соблюдена ли иерархия, которую ожидает веб-сервис.

← На главную