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

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

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

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

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

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

Если мы работаем с данными формы (например, ДанныеФормыКоллекция), то при передаче их на сервер платформа обычно справляется сама. Но если мы собрали данные программно на клиенте (например, массив подобранных товаров, результат чтения файла Excel на клиенте и т.д.), нам потребуются специальные механизмы.

Проанализируем два основных метода решения этой проблемы:

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

Способ 1: Передача через Массив Структур

Если нам необходимо передать небольшое количество строк (например, список из 10-50 товаров, которые пользователь подобрал в корзину), самым простым и "легким" способом будет использование примитивных коллекций: Массив и Структура.

Эти типы данных существуют и на клиенте, и на сервере, и отлично сериализуются. Давайте рассмотрим алгоритм действий.

На стороне Клиента мы формируем массив, где каждая строка нашей будущей таблицы будет представлена в виде Структуры:


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

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


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

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

Способ 2: Использование Временного хранилища

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

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

Давайте рассмотрим сценарий, когда данные все-таки есть на клиенте (например, данные формы, преобразованные в структуру) и мы хотим использовать хранилище для надежности.

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

Посмотрим на пример решения задачи "Загрузка из Excel на клиенте и обработка на сервере". Это классический пример передачи данных.

Этап 1: Подготовка на Клиенте


&НаКлиенте
Процедура ЗагрузитьИОбработать(Команда)
    
    // Предположим, мы прочитали файл и у нас есть массив структур (как в примере 1)
    // Но данных очень много (10 000 строк).
    // Передавать их параметром процедуры - плохой тон (забивает канал).
    
    // Помещаем данные во временное хранилище
    // УникальныйИдентификатор - привязывает хранилище к жизни этой формы
    АдресХранилища = ПоместитьВоВременноеХранилище(МассивДанных, УникальныйИдентификатор);
    
    // Передаем ТОЛЬКО строковый адрес
    ОбработатьДанныеВФоне(АдресХранилища);
    
КонецПроцедуры

Этап 2: Получение на Сервере


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

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

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

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

Давайте посмотрим, как правильно конвертировать данные формы в таблицу значений на сервере.


&НаКлиенте
Процедура ВыполнитьДействие(Команда)
    // Просто вызываем серверный метод. Данные формы (Объект) доступны там автоматически,
    // если метод &НаСервере (с контекстом).
    ОбработкаТЧНаСервере();
КонецПроцедуры

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

Если же мы используем модуль &НаСервереБезКонтекста (что рекомендуется для быстродействия), то передать ДанныеФормыКоллекция (ТЧ) можно, но на сервере она не превратится автоматически в ТЗ. Платформа видит её как специальный объект. В этом случае часто также используют конвертацию в массив структур или временное хранилище, если данных много.

Ошибки при передаче (Troubleshooting)

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

  1. Ошибка: "Поле объекта не обнаружено" при обращении к ТаблицеЗначений на клиенте.
    Причина: Вы пытаетесь вернуть ТЗ с сервера на клиент.
    Решение: Преобразуйте ТЗ в массив структур перед возвратом на клиент.
  2. Ошибка: "Ошибка параметра 1: Нельзя передавать мутабельные значения".
    Причина: Попытка передать сам объект формы или сложную коллекцию в фоновое задание или через определенные границы сеансов.
    Решение: Используйте ПоместитьВоВременноеХранилище.
  3. Потеря данных при использовании временного хранилища.
    Причина: При помещении не указан UUID формы (второй параметр), и при завершении серверного вызова временное хранилище очищается.
    Решение: Всегда передавайте УникальныйИдентификатор формы, если данные нужны надолго.

Итоги

Для эффективной работы с табличными данными между клиентом и сервером используйте следующие правила:

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

← На главную