Почему возникает ошибка передачи данных между клиентом и сервером и как её исправить?

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

В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с загадочной ошибкой: Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа. Ошибка преобразования данных XDTO. Самое странное в этой ситуации то, что разработчик может быть уверен: он передает только простые типы данных, такие как строки или числа, и ничего не возвращает назад. Однако система утверждает обратное.

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

Анализ исходной проблемы

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


&НаКлиенте
Процедура ТабличнаяЧасть1ОдинПриИзменении(Элемент)
    // Вызов сервера с передачей простых параметров
    СделатьКрасиво(ЗначениеАктивнойЯчейки, НомерТекСтроки, ИмяКолонки);
КонецПроцедуры

&НаСервере
Процедура СделатьКрасиво(ЗначениеАктивнойЯчейки, Строка, Колонка)
    // Получение таблицы для анализа
    ТекТаблица = Объект.Таблица.Выгрузить(,"Один,Два,Три...");
    
    Сч = 0;
    // Цикл, в котором используется имя "Колонка"
    Для Каждого Колонка Из ТекТаблица.Колонки Цикл
        // Какая-то логика
        Сч = Сч + 1;
    КонецЦикла;

    // Работа с объектом
    ТекОбъект = РеквизитФормыВЗначение("Объект");
    ТекОбъект.Таблица[0].ЦветЯчейкиОдин = Перечисления.ЦветаЯчеек.Красный;
    ЗначениеВРеквизитФормы(ТекОбъект, "Объект");    
КонецПроцедуры

Несмотря на то, что в процедуру СделатьКрасиво передаются строка и число, при завершении её работы возникает ошибка XDTO: Отсутствует отображение для типа 'КолонкаТаблицыЗначений'. Выясним причину этого поведения.

Механизм передачи параметров «по ссылке»

Проанализируем, как платформа 1С обрабатывает параметры процедур. По умолчанию все параметры в 1С передаются по ссылке. Это означает, что если внутри вызываемой процедуры (даже на сервере) значение переменной-параметра изменится, это измененное значение должно быть возвращено обратно в вызывающий код на клиенте.

В нашем примере в заголовке процедуры указан параметр Колонка. Внутри процедуры программист использовал цикл Для Каждого Колонка Из ТекТаблица.Колонки Цикл. В этот момент переменной Колонка, которая изначально была строкой, присваивается объект типа КолонкаТаблицыЗначений.

Когда выполнение серверной процедуры завершается, платформа пытается выполнить синхронизацию данных. Она берет текущее значение переменной Колонка (которая теперь является объектом серверного типа) и пытается отправить его на клиент. Но тип КолонкаТаблицыЗначений не существует на клиенте и не может быть сериализован в XML-пакет (XDTO). В этот момент и происходит аварийное завершение работы программы.

Решение №1: Использование ключевого слова Знач

Самый надежный способ предотвратить подобные ошибки — использовать передачу параметров по значению. Для этого перед именем параметра в объявлении процедуры следует добавить ключевое слово Знач. Рассмотрим исправленный заголовок:


&НаСервере
Процедура СделатьКрасиво(Знач ЗначениеАктивнойЯчейки, Знач Строка, Знач Колонка)
    // Теперь изменения этих переменных внутри процедуры 
    // не будут отправляться обратно на клиент
КонецПроцедуры

Использование Знач не только защищает от ошибок типизации, но и немного повышает производительность, так как платформе не нужно тратить ресурсы на упаковку и обратную передачу данных, которые клиенту не нужны.

Решение №2: Гигиена имен переменных

Проанализируем важность именования локальных переменных. Ошибка в примере возникла из-за того, что имя итератора цикла совпало с именем входного параметра. Хорошей практикой является использование префиксов для локальных переменных или более описательных имен. Посмотрим, как можно переписать цикл:


Для Каждого ТекКолонка Из ТекТаблица.Колонки Цикл
    // Используем ТекКолонка, чтобы не затирать входной параметр Колонка
    СвязьНомеровИИменКолонок.Вставить(ТекКолонка.Имя, Сч);
КонецЦикла;

В этом случае переменная Колонка сохранит свое исходное строковое значение, и при возврате на клиент ошибки не возникнет.

Важные замечания по типам данных (Сериализация)

Нужно помнить, что между клиентом и сервером могут перемещаться только сериализуемые типы данных. К ним относятся:

  1. Простые типы: Число, Строка, Дата, Булево.
  2. Ссылки на объекты базы данных (например, СправочникСсылка.Номенклатура).
  3. Универсальные коллекции: Структура, Массив, СписокЗначений, Соответствие (при условии, что их элементы также сериализуемы).
  4. Реквизиты формы и данные формы (ДанныеФормыСтруктура, ДанныеФормыКоллекция).

К типам, которые категорически нельзя передавать (и возвращать), относятся: ТаблицаЗначений, СтрокаТаблицыЗначений, Запрос, РезультатЗапроса, COMОбъект и любые менеджеры объектов.

Оптимизация работы с методами преобразования

В исходном коде автора также используются методы РеквизитФормыВЗначение и ЗначениеВРеквизитФормы. Проанализируем ситуацию: эти методы очень ресурсоемкие. При вызове РеквизитФормыВЗначение("Объект") платформа создает на сервере полную копию объекта (например, документа) со всеми его табличными частями. Если в документе тысячи строк, это приведет к значительным задержкам.

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

Выясним причину ошибки с помощью отладки: если вы столкнулись с подобным сообщением, поставьте точку останова на последней строке серверной процедуры (КонецПроцедуры) и проверьте в табло типы всех входящих параметров. Если тип параметра изменился с Строка на какой-то сложный объект — вы нашли виновника.

← На главную