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