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