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