Как правильно передать таблицу или массив данных с клиента на сервер в 1С?

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

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

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

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

Для начала разберемся в архитектуре управляемого приложения. Платформа 1С четко разделяет контексты выполнения кода:

  1. Клиент (Тонкий клиент, Веб-клиент) — здесь происходит взаимодействие с пользователем. Набор доступных типов данных здесь сильно ограничен.
  2. Сервер — здесь происходит основная обработка данных, запись в базу и сложные вычисления.

Объект ТаблицаЗначений в 1С доступен только на сервере (и в толстом клиенте). На тонком клиенте создать или использовать Таблицу Значений невозможно. Если вы попытаетесь передать переменную, содержащую недопустимый для клиента тип, или "мутабельный" (изменяемый) объект между контекстами неправильно, платформа выдаст исключение.

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

Способ 1. Использование Массива Структур (для небольших объемов данных)

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

Разберем алгоритм действий:

  1. На клиенте создаем Массив.
  2. В цикле заполняем его элементами типа Структура, где ключи — это имена колонок, а значения — данные ячеек.
  3. Передаем этот массив параметром в серверную процедуру.
  4. На сервере при необходимости преобразуем массив обратно в Таблицу Значений или обрабатываем как есть.

Рассмотрим пример кода на клиенте:


&НаКлиенте
Процедура ОбработатьДанные(Команда)
    
    // Создаем коллекцию данных
    МассивДанных = Новый Массив;
    
    // Имитация заполнения данными (например, из файла)
    Для Счетчик = 1 По 5 Цикл
        СтрокаДанных = Новый Структура;
        СтрокаДанных.Вставить("Товар", "Товар " + Строка(Счетчик));
        СтрокаДанных.Вставить("Количество", 10 * Счетчик);
        
        МассивДанных.Добавить(СтрокаДанных);
    КонецЦикла;
    
    // Передаем массив на сервер
    ОбработатьНаСервере(МассивДанных);
    
КонецПроцедуры

Код приемника на сервере:


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

Способ 2. Использование Временного Хранилища (для больших объемов)

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

Проанализируем этот метод подробнее. Он особенно полезен, когда данные формируются на клиенте, но "весят" много, или когда мы хотим передать файл.

Важный нюанс: Если мы говорим о Таблице Значений, то, как мы выяснили, на клиенте её создать нельзя. Но мы можем поместить во временное хранилище тот же массив структур или файл, а на сервере его восстановить.

Рассмотрим пример использования методов ПоместитьВоВременноеХранилище и ПолучитьИзВременногоХранилища.

Алгоритм действий:

  1. На клиенте подготавливаем данные (например, Массив структур или ДвоичныеДанные файла).
  2. Помещаем данные в хранилище, указывая УникальныйИдентификатор формы (чтобы данные жили, пока жива форма).
  3. Получаем строковый адрес.
  4. Передаем только адрес (строку) в серверную процедуру.
  5. На сервере извлекаем данные по адресу.

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


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

&НаСервере
Процедура ВыполнитьОбработкуНаСервере(АдресДанных)
    
    // Извлекаем данные из хранилища
    ПолученныеДанные = ПолучитьИзВременногоХранилища(АдресДанных);
    
    Если ТипЗнч(ПолученныеДанные) = Тип("Массив") Тогда
        // Обрабатываем массив
    КонецЕсли;
    
КонецПроцедуры

Работа с реквизитами формы (ДанныеФормыКоллекция)

Отдельно рассмотрим ситуацию, когда таблица уже есть на форме (вы видите её в интерфейсе, например, табличная часть документа или таблица на форме обработки). В этом случае объект имеет тип ДанныеФормыКоллекция.

Ошибка новичка: Пытаться передать Объект.Товары (где Объект — реквизит формы) в процедуру &НаСервереБезКонтекста. Решение: В процедурах &НаСервере (с контекстом) вся структура формы (Объект, ЭтаФорма) видна автоматически. Передавать её параметром не нужно. Вы просто обращаетесь к Объект.Товары внутри серверной процедуры.

Если же вам нужно преобразовать данные формы в настоящую ТаблицаЗначений для обработки запросом или выгрузки, используйте метод РеквизитФормыВЗначение:


&НаСервере
Процедура РаботаСДаннымиФормы()
    
    // Преобразуем данные формы в полноценный объект прикладного типа (Документ, Справочник, Обработка)
    ПрикладнойОбъект = РеквизитФормыВЗначение("Объект");
    
    // Теперь у нас есть доступ к ТЗ как к части объекта
    ТЗТовары = ПрикладнойОбъект.Товары.Выгрузить();
    
    // ... какие-то действия с ТЗ ...
    
    // Если мы меняли ТЗ и хотим вернуть изменения на форму:
    ПрикладнойОбъект.Товары.Загрузить(ТЗТовары);
    ЗначениеВРеквизитФормы(ПрикладнойОбъект, "Объект");
    
КонецПроцедуры

Резюме

Подводя итог, выделим главные правила передачи коллекций с клиента на сервер:

  1. Не пытайтесь создать ТаблицаЗначений на тонком клиенте — это невозможно.
  2. Для передачи простых списков используйте Массив структур.
  3. Для передачи больших объемов данных или файлов используйте пару методов ПоместитьВоВременноеХранилище (клиент) и ПолучитьИзВременногоХранилища (сервер).
  4. Если данные уже находятся в реквизитах управляемой формы, используйте контекстный вызов сервера и метод РеквизитФормыВЗначение для конвертации в прикладные объекты.
← На главную