Как правильно передать результат запроса или таблицу значений с сервера на клиент в 1С?

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

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

Почему возникает «Ошибка отображения типов»?

Для начала проанализируем ситуацию: тонкий клиент — это «легкое» приложение, которое отвечает только за отображение интерфейса и простую логику. На стороне клиента физически отсутствуют программные библиотеки для работы с тяжелыми объектами, такими как Запрос, РезультатЗапроса или ТаблицаЗначений. Эти объекты предназначены для работы в серверном адресном пространстве, где есть прямой доступ к СУБД и ресурсам системы.

Когда платформа пытается передать объект с сервера на клиент, она выполняет сериализацию — превращает объект в последовательность байтов (обычно в формате XML/XDTO). Однако ТаблицаЗначений является мутабельным типом. Это означает, что объект не просто хранит данные, но и обладает сложным состоянием: индексами, типами колонок и методами, которые невозможно однозначно воссоздать на стороне «бедного» клиента. Поэтому попытка передать такой тип вызывает отказ системы безопасности и сериализации.

Способ 1. Преобразование в массив структур (Универсальный метод)

Если нам нужно просто обработать данные запроса на клиенте (например, перебрать их в цикле или заполнить список), самым правильным решением будет конвертация данных в простые коллекции: Массив и Структура. Эти типы данных являются универсальными и прекрасно передаются между контекстами.

Рассмотрим пример кода, который решает задачу преобразования:


&НаСервере
Функция ПолучитьДанныеТоваровСервер()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Товары.Наименование КАК Наименование,
        |	Товары.Артикул КАК Артикул,
        |	Товары.Цена КАК Цена
        |ИЗ
        |	Справочник.Товары КАК Товары";
    
    ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
    
    // Создаем массив для хранения структур
    СписокДанных = Новый Массив;
    
    Для Каждого СтрокаТЗ Из ТаблицаРезультата Цикл
        
        // Каждую строку превращаем в структуру
        НоваяСтрока = Новый Структура;
        НоваяСтрока.Вставить("Наименование", СтрокаТЗ.Наименование);
        НоваяСтрока.Вставить("Артикул", СтрокаТЗ.Артикул);
        НоваяСтрока.Вставить("Цена", СтрокаТЗ.Цена);
        
        СписокДанных.Добавить(НоваяСтрока);
        
    КонецЦикла;
    
    Возврат СписокДанных;

КонецФункции

&НаКлиенте
Процедура ОбработатьДанные(Команда)
    
    // Теперь данные успешно передаются без ошибок
    МассивРезультатов = ПолучитьДанныеТоваровСервер();
    
    Для Каждого Элемент Из МассивРезультатов Цикл
        Сообщить(Элемент.Наименование + ": " + Элемент.Цена);
    КонецЦикла;
    
КонецПроцедуры

Важный нюанс: при формировании структуры на сервере следите за тем, чтобы значения полей (ячейки таблицы) сами не были мутабельными. Если в колонке таблицы лежит СправочникОбъект или ДокументОбъект, ошибка повторится. На клиент можно передавать только Ссылки, числа, строки, даты и булево.

Способ 2. Использование реквизитов формы (ДанныеФормыКоллекция)

Часто программисты задаются вопросом: «Но ведь на форме есть таблицы, и они работают!». Это происходит потому, что платформа использует специальный промежуточный тип данных — ДанныеФормыКоллекция. Если ваша задача — отобразить результат запроса в таблице на экране, не нужно вручную создавать массивы структур.

Выясним, как это сделать через механизм ЗначениеВРеквизитФормы. Предположим, у вас на форме создан реквизит СписокТоваров с типом ТаблицаЗначений, заполнить который можно через универсальную функцию получения результата СКД.


&НаСервере
Процедура ЗаполнитьТаблицуНаФормеСервер()
    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ * ИЗ Справочник.Товары";
    Результат = Запрос.Выполнить().Выгрузить();
    
    // Автоматическая конвертация ТЗ в ДанныеФормыКоллекция
    ЗначениеВРеквизитФормы(Результат, "СписокТоваров");
    
КонецПроцедуры

Этот метод работает максимально быстро, так как выполняется на уровне ядра платформы. ДанныеФормыКоллекция — это своего рода «проекция» таблицы, которая умеет жить на клиенте и синхронизироваться с сервером.

Способ 3. Передача через временное хранилище

Проанализируем ситуацию, когда данных очень много, и передавать их через параметры функции накладно для производительности. Можно использовать Временное хранилище. Однако помните, что само хранилище не делает ТаблицуЗначений доступной на клиенте. Оно лишь позволяет сохранить её в памяти сервера и получить «адрес» в виде строки.

Алгоритм работы следующий:

  1. На сервере помещаем ТаблицуЗначений в хранилище и получаем Адрес.
  2. Передаем этот Адрес (строку) на клиент.
  3. Когда клиенту снова понадобятся эти данные для другого серверного вызова, он вернет Адрес обратно на сервер.


&НаСервере
Функция СохранитьДанныеВоВременномХранилище()
    
    ТЗ = Новый ТаблицаЗначений;
    // ... заполнение таблицы ...
    
    // Уникальный идентификатор формы гарантирует удаление данных при закрытии окна
    Адрес = ПоместитьВоВременноеХранилище(ТЗ, ЭтаФорма.УникальныйИдентификатор);
    
    Возврат Адрес;
    
КонецФункции

Попытка вызвать ПолучитьИзВременногоХранилища(Адрес) на клиенте всё равно приведет к ошибке отображения типов, если внутри лежит ТЗ. Этот способ подходит только для транспортировки данных между серверными процедурами.

Способ 4. Сериализация в JSON (Для больших объемов)

Разберем современный подход, который часто оказывается быстрее ручного перебора строк в цикле. Платформа 1С поддерживает высокоскоростную сериализацию коллекций в формат JSON. Это особенно полезно, если вам нужно передать структуру данных во внешнюю систему или веб-клиент.


&НаСервере
Функция ПолучитьДанныеВФорматеJSON()
    
    ТЗ = ПолучитьТаблицуДанных(); // Ваша функция получения ТЗ
    
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, ТЗ);
    
    Возврат ЗаписьJSON.Закрыть(); // Возвращаем обычную строку
    
КонецФункции

На клиенте вы получите обычную строку, которую можно либо хранить, либо разобрать обратно в структуру с помощью объекта ЧтениеJSON. Это эффективный способ «обмануть» ограничения типизации, передавая сложные данные в виде текстового потока.

Резюме

Подводя итог нашему анализу, закрепим основные правила:

Соблюдение этих правил архитектуры 1С позволит вам создавать стабильные и быстрые приложения без ошибок отображения типов.

← На главную