В процессе разработки на платформе 1С в управляемых формах можно столкнуться с неожиданной и нелогичной на первый взгляд ошибкой: "Ошибка преобразования данных XDTO". Особенно неприятно, когда она возникает при передаче на сервер простых типов данных, таких как число или строка. Давайте детально разберем ситуацию, с которой столкнулся автор на форуме, проанализируем причины и найдем надежное решение.
Исходная проблема выглядит следующим образом. В модуле управляемой формы есть серверная процедура с несколькими необязательными параметрами:
&НаСервере
Процедура ЗаполнитьПоИсторииНаСервере(ТекСпособ = "", НомТекСтроки = 0, масПлатежи = Неопределено)
// ... код процедуры ...
КонецПроцедуры
При попытке вызвать эту процедуру с клиента, пропуская первый параметр, который имеет значение по умолчанию, возникает ошибка:
// Такой вызов приводит к ошибке
ЗаполнитьПоИсторииНаСервере(, 1);
Система возвращает сообщение:
Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа.
по причине:
Ошибка преобразования данных XDTO
Главный вопрос: почему это происходит, ведь мы передаем простое число, а остальные параметры имеют значения по умолчанию? Давайте разбираться.
Ошибка преобразования данных XDTO (XML Data Transfer Objects) говорит о том, что механизм платформы 1С не смог корректно преобразовать (сериализовать) данные для их передачи с клиента на сервер. Хотя в нашем случае передаются простые типы, проблема кроется не в самих данных, а в особенностях их обработки платформой при определенной структуре вызова.
Выделим несколько вероятных причин:
Процедура( , Значение2)), механизм сериализации может некорректно сформировать пакет данных. Платформа может испытывать трудности с правильным сопоставлением переданных значений с ожидаемыми параметрами на сервере, что и приводит к сбою.&НаСервере неявно передает на сервер весь контекст формы (ее реквизиты и их значения). Если на форме есть реквизит с типом, который по какой-то причине не может быть сериализован (например, сложный объект или данные, поврежденные в ходе работы), это может спровоцировать ошибку XDTO, даже если этот реквизит никак не используется в вызываемой процедуре.Рассмотрим несколько подходов к решению этой задачи, от самого надежного до общих рекомендаций.
Это решение, которое помогло автору вопроса, и оно является наиболее стабильным и универсальным. Вместо передачи нескольких отдельных параметров мы упаковываем их в один объект-контейнер — Структура или ФиксированнаяСтруктура.
Почему это работает? Платформе гораздо проще и надежнее сериализовать один структурированный объект, чем разбирать последовательность позиционных параметров, особенно с пропусками. Это устраняет любую двусмысленность и стабильно работает на разных версиях платформы.
Разберем по шагам, как это реализовать:
1. Изменяем клиентский вызов.
На клиенте перед вызовом серверной процедуры создаем структуру и заполняем ее нужными параметрами. Затем передаем эту структуру как единый параметр.
&НаКлиенте
Процедура КомандаЗаполнить()
// Создаем структуру для передачи параметров на сервер
ПараметрыВызова = Новый Структура;
ПараметрыВызова.Вставить("ТекСпособ", ""); // Передаем пустое значение, как и требовалось
ПараметрыВызова.Вставить("НомТекСтроки", 1);
ПараметрыВызова.Вставить("масПлатежи", Неопределено);
// Вызываем серверную процедуру, передавая один параметр - структуру
ЗаполнитьПоИсторииНаСервере(ПараметрыВызова);
КонецПроцедуры
2. Адаптируем серверную процедуру.
Теперь серверная процедура должна принимать один параметр (нашу структуру) и извлекать из него необходимые данные.
&НаСервере
Процедура ЗаполнитьПоИсторииНаСервере(Параметры)
// Распаковываем параметры из структуры
ТекСпособ = Параметры.ТекСпособ;
НомТекСтроки = Параметры.НомТекСтроки;
масПлатежи = Параметры.масПлатежи;
// ... дальнейший код процедуры, который использует эти переменные ...
Сообщить("Способ: " + ТекСпособ + ", Номер строки: " + НомТекСтроки);
КонецПроцедуры
Этот подход не только решает проблему с ошибкой XDTO, но и делает код более читаемым и гибким. Если в будущем потребуется передать еще один параметр, нужно будет просто добавить новое свойство в структуру, не меняя сигнатуру процедуры.
Хотя упаковка в структуру является лучшим решением, рассмотрим и другие варианты, которые стоит попробовать при столкновении с подобными ошибками.
1. Явная передача всех параметров.
Первая мысль, которая приходит в голову, — это не пропускать параметры, а передать их явно, используя значения по умолчанию. Например:
// Попытка передать все параметры явно
ЗаполнитьПоИсторииНаСервере("", 1, Неопределено);
В некоторых случаях это может сработать. Однако в конкретной ситуации на форуме этот способ также приводил к ошибке, что лишний раз указывает на более глубокую, возможно, платформенную проблему с обработкой вызова.
2. Использование директивы &НаСервереБезКонтекста.
Если ваша серверная процедура не требует доступа к данным формы (реквизитам, элементам), попробуйте заменить директиву &НаСервере на &НаСервереБезКонтекста.
&НаСервереБезКонтекста
Процедура ЗаполнитьПоИсторииНаСервере(ТекСпособ = "", НомТекСтроки = 0, масПлатежи = Неопределено)
// ... код процедуры ...
КонецПроцедуры
Это отключает передачу контекста формы на сервер. Такой вызов становится "легче" и быстрее, а также может решить проблему, если она была связана с сериализацией какого-либо реквизита формы.
3. Обновление платформы 1С.
Учитывая, что проблема была зафиксирована на версии 8.3.12, самым кардинальным и правильным решением в долгосрочной перспективе является обновление платформы до более актуального релиза. Весьма вероятно, что данная ошибка уже исправлена разработчиками.
Вывод: столкнувшись с ошибкой XDTO при вызове серверной процедуры с пропущенными параметрами, самым надежным и быстрым решением является рефакторинг кода с использованием структуры для передачи параметров. Это стабильный и рекомендуемый подход, который защитит вас от подобных платформенных особенностей.