Как передать таблицу значений с сервера на клиент в 1С:Предприятии 8.3

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

При разработке в среде 1С:Предприятие 8 (начиная с версии 8.2 и заканчивая актуальными релизами 8.3) программисты часто сталкиваются с фундаментальным ограничением управляемого приложения: объект типа ТаблицаЗначений не может существовать на клиенте (в тонком или веб-клиенте). Этот тип данных предназначен исключительно для серверных вычислений. Если мы попытаемся вернуть ТаблицаЗначений напрямую из функции с директивой &НаСервере в процедуру &НаКлиенте, платформа выдаст ошибку сериализации.

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

Причины ограничения типа ТаблицаЗначений

Выясним причину, по которой фирма "1С" запретила использование таблиц значений на клиенте. В первую очередь это связано с архитектурой Тонкого клиента. Таблица значений — это "тяжелый" объект, обладающий мощными методами индексирования, поиска и свертки. Реализация этих механизмов на стороне клиента потребовала бы значительных ресурсов и усложнила бы работу веб-клиента, где исполняемый код транслируется в JavaScript. Для передачи данных между слоями приложения используются облегченные структуры, которые легко сериализуются в XML или JSON.

Решение 1: Преобразование таблицы значений в массив структур

Это самый популярный и универсальный метод. Суть его заключается в том, что мы обходим каждую строку таблицы на сервере, упаковываем данные в объект типа Структура, где ключами являются имена колонок, и добавляем эти структуры в объект типа Массив. Массивы и структуры прекрасно передаются на клиент.

Рассмотрим пример кода, реализующий этот подход вручную:


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

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

Если в вашей конфигурации используется Библиотека стандартных подсистем (БСП), мы можем упростить себе задачу и воспользоваться готовой функцией общего модуля ОбщегоНазначения.ТаблицаЗначенийВМассив(). Это стандарт де-факто для современной разработки на 1С.

Решение 2: Использование ДанныеФормыКоллекция

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

Проанализируем ситуацию: платформа автоматически синхронизирует реквизиты формы между сервером и клиентом. Мы можем заполнить этот реквизит на сервере методом ЗначениеВРеквизитФормы().


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

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

Важный момент: объект ДанныеФормыКоллекция на клиенте поддерживает многие методы таблицы значений, такие как НайтиСтроки() или Сортировать(), что делает его крайне удобным для интерактивной работы.

Решение 3: Оптимизированная структура массивов

Когда данных очень много (десятки тысяч строк), массив структур становится невыгодным из-за большого объема служебной информации (каждая структура хранит имена ключей). В этом случае рассмотрим метод "Структура массивов". Суть его в том, что мы создаем структуру, где количество ключей равно количеству колонок, а значением каждого ключа является массив с данными этой колонки.

Посмотрим на пример реализации:


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

На клиенте работа с такой структурой будет выглядеть так: Значение = Результат.Наименование[Индекс];. Этот способ значительно экономит оперативную память и ускоряет передачу данных по сети.

Решение 4: Использование временного хранилища

Иногда таблицу не нужно обходить на клиенте, а нужно просто "пронести" её из одной серверной процедуры в другую через клиентский вызов. В этом случае идеальным решением будет Временное хранилище. Мы помещаем таблицу в хранилище на сервере, получаем уникальный строковый адрес, передаем этот адрес на клиент, а затем обратно на сервер.


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

На клиенте мы храним только АдресВХранилище (тип Строка), что практически не нагружает систему.

Решение 5: Недокументированный хак через ОписаниеТипов

Как обсуждалось в сообщении 22 темы форума, существует способ "обмануть" платформу и создать объект типа ТаблицаЗначений прямо в тонком клиенте. Платформа запрещает конструктор Новый ТаблицаЗначений, но позволяет создавать объекты по их типу через ОписаниеТипов.

Разберем этот метод подробнее (использовать с осторожностью!):


&НаКлиенте
Процедура СоздатьТЗНаКлиенте()
    Попытка
        ОписаниеТипа = Новый ОписаниеТипов("ТаблицаЗначений");
        ТЗ = Новый(ОписаниеТипа.Типы()[0]);
        
        ТЗ.Колонки.Добавить("ИмяПользователя");
        НоваяСтрока = ТЗ.Добавить();
        НоваяСтрока.ИмяПользователя = "Администратор";
        
        Сообщить("Объект создан успешно! Тип: " + ТипЗнч(ТЗ));
    Исключение
        Сообщить("Метод не поддерживается в данной версии или клиенте.");
    КонецПопытки;
КонецПроцедуры

Внимание: Этот метод может не работать в веб-клиенте, так как браузерный движок не содержит реализации методов ТаблицаЗначений. Кроме того, такую таблицу всё равно нельзя будет передать обратно на сервер напрямую (возникнет ошибка соответствия типов). Используйте этот метод только для локальных временных расчетов в тонком клиенте, если вам действительно не хватает функционала массивов и соответствий.

Подведение итогов

Мы проанализировали основные сценарии работы с табличными данными в 1С. Подведем итоги выбора метода:

  1. Если нужно просто перебрать данные в цикле на клиенте — используйте Массив структур (или БСП ОбщегоНазначения.ТаблицаЗначенийВМассив()).
  2. Если данные нужно показать пользователю или активно менять на форме — используйте ДанныеФормыКоллекция через реквизит формы.
  3. Если данных критически много — используйте Структуру массивов.
  4. Если таблицу нужно сохранить между серверными вызовами без изменений — используйте Временное хранилище.

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

← На главную