К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как передать табличную часть с клиента на сервер в 1С

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

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

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

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

Почему табличную часть нельзя просто «взять» с клиента

В управляемом приложении клиент и сервер — это разные контексты исполнения. На клиенте форма работает с данными в виде «ДанныеФормыСтруктура» и «ДанныеФормыКоллекция», а настоящий объект (например, «ДокументОбъект.РеализацияТоваровУслуг») существует только в момент серверного вызова. Типы «ТаблицаЗначений» и «ДанныеФормыКоллекция» нельзя передать параметром в серверную процедуру — платформа выдаст ошибку о недопустимом типе параметра.

Кроме того, любой вызов сервера — это сетевой обмен с сериализацией данных. Передавать лишние данные туда-обратно дорого по производительности, поэтому платформа намеренно ограничивает набор типов, допустимых для передачи, и поощряет обращение к данным объекта непосредственно на сервере.

Способ 1. Обращение к реквизиту «Объект» в серверной процедуре

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

Клиентская часть выглядит так:

&НаКлиенте

Процедура РассчитатьСкидку(Команда)

РассчитатьСкидкуНаСервере();

КонецПроцедуры

Серверная процедура работает с табличной частью напрямую:

&НаСервере

Процедура РассчитатьСкидкуНаСервере()

Для Каждого СтрокаТовары Из Объект.Товары Цикл

СтрокаТовары.Сумма = СтрокаТовары.Количество * СтрокаТовары.Цена;

КонецЦикла;

КонецПроцедуры

После завершения серверной процедуры платформа автоматически вернёт изменённые данные формы на клиент, и пользователь увидит пересчитанные суммы. Никакой «передачи» в явном виде не происходит — форма сериализуется на сервер и обратно целиком.

Способ 2. Передача строк табличной части массивом структур

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

&НаКлиенте

Процедура ЗаполнитьЦены(Команда)

ДанныеСтрок = Новый Массив;

Для Каждого СтрокаТовары Из Объект.Товары Цикл

ДанныеСтрок.Добавить(Новый Структура("Номенклатура, Количество",

СтрокаТовары.Номенклатура, СтрокаТовары.Количество));

КонецЦикла;

Цены = ПолучитьЦеныНаСервере(ДанныеСтрок);

Для Каждого СтрокаЦены Из Цены Цикл

// поиск строки и заполнение цены

КонецЦикла;

КонецПроцедуры

На сервере массив обходится обычным циклом, значения доступны как свойства структуры. Обратите внимание: передавать нужно только те поля, которые реально нужны серверу. Копирование всех колонок табличной части «на всякий случай» увеличивает трафик и замедляет вызов, особенно при сотнях строк.

Недостаток способа — ручное сопоставление строк при возврате результата. Чтобы не потерять связь, включайте в структуру номер строки или уникальный ключ и по нему находите исходную строку на клиенте.

Способ 3. Выгрузка в таблицу значений через временное хранилище

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

&НаСервере

Процедура ОбработатьНаСервере()

ТаблицаТоваров = Объект.Товары.Выгрузить();

АдресХранилища = ПоместитьВоВременноеХранилище(ТаблицаТоваров, УникальныйИдентификатор);

// дальнейшая обработка, например запросом

КонецПроцедуры

Для реквизита формы типа «ТаблицаЗначений» (не связанного с объектом) используется пара методов: на клиенте данные доступны как «ДанныеФормыКоллекция», а на сервере в бесконтекстной процедуре таблицу восстанавливают через ПолучитьИзВременногоХранилища(Адрес). Помещение в хранилище выполняется в серверной процедуре формы, где доступен метод РеквизитФормыВЗначение или выгрузка коллекции.

Сравнение способов и условия выбора

СпособКогда применятьОграничения
Обращение к Объект на сервереФорма документа или справочника, обработка всей табличной частиТолько в модуле формы, только для реквизита «Объект»
Массив структурВызов общего серверного модуля, нужна часть колонок или строкРучное сопоставление строк при возврате результата
Выгрузка в хранилищеНужна таблица значений для запроса или пакетной обработкиДорого при большом объёме, требуется очистка хранилища
Маршрут решения

Как выбрать действие

Обработка выполняется в модуле той же формы объектаИспользуйте контекстный вызов &НаСервере и работайте с Объект.ИмяТабличнойЧасти
Логика вынесена в общий серверный модульСоберите нужные поля в массив структур и передайте параметром
На сервере нужен запрос по данным таблицыВыгрузите коллекцию в таблицу значений и передайте через временное хранилище

Пошаговый порядок внедрения

Независимо от выбранного способа последовательность внедрения одинакова. Сначала определите, где будет исполняться обработка — в модуле формы или в общем модуле, от этого зависит необходимость передачи данных. Затем напишите серверную процедуру и только после этого — клиентскую обёртку с вызовом.

Порядок действий
  1. 1
    Определите, доступен ли реквизит Объект на сервере (форма объекта) или таблица независимая
  2. 2
    Напишите серверную процедуру с нужной директивой (&НаСервере или &НаСервереБезКонтекста)
  3. 3
    При бесконтекстном вызове соберите данные в массив структур с минимально необходимым набором полей
  4. 4
    Добавьте клиентскую процедуру-обработчик команды, вызывающую серверную
  5. 5
    Проверьте на тестовом документе: значения в табличной части изменились, строки не потеряны
  6. 6
    Проверьте поведение при пустой табличной части и при большом количестве строк

Проверка результата и типичные ошибки

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

Контрольные точки

Как проверить результат

Значения в табличной части после вызова
Норма

Пересчитанные данные видны на форме сразу

Тревожный признак

Изменения появляются только после перезаписи или переоткрытия формы

Количество строк до и после вызова
Норма

Совпадает, порядок строк сохранён

Тревожный признак

Строки потеряны или перемешаны — ошибка сопоставления при возврате

Поведение при пустой табличной части
Норма

Процедура завершается без ошибок

Тревожный признак

Ошибка обращения к индексу или к свойству неопределённого значения

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

Типичные ошибки
01
Передача всей табличной части массивом структур, когда достаточно контекстного вызова — лишний трафик и лишний код
02
Использование &НаСервереБезКонтекста с обращением к Объект — ошибка исполнения, так как контекст формы на сервер не передаётся
03
Возврат результата без ключа связи со строкой — данные записываются не в те строки
04
Игнорирование Модифицированность формы — после серверной обработки документ не помечается как изменённый, и пользователь может потерять данные при закрытии

Ограничения и нюансы производительности

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

При передаче массивом структур помните, что типы значений должны быть сериализуемыми: ссылки, примитивные типы, даты передаются без проблем, а вот «ХранилищеЗначения» или COM-объекты — нет. Если табличная часть содержит сотни строк, собирайте структуры порциями или пересмотрите архитектуру в пользу контекстного вызова.

Если серверная обработка занимает заметное время, полезно вывести пользователю индикатор через ПоказатьОповещениеПользователя или состояние формы до вызова, иначе на медленном соединении создаётся впечатление зависания программы.
ПЗ
Практическое замечание

Частые вопросы

Можно ли передать табличную часть параметром в обычном приложении?

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

Чем отличается &НаСервере от &НаСервереБезКонтекста?

Директива &НаСервере сохраняет контекст формы: на сервере доступны реквизиты, включая Объект с табличными частями. &НаСервереБезКонтекста исполняется без данных формы — быстрее по трафику, но все нужные данные придётся передать параметрами допустимых типов.

Как передать только выделенные строки табличной части?

На клиенте обойдите коллекцию Элементы.ИмяТаблицы.ВыделенныеСтроки, получите данные каждой строки через НайтиПоИдентификатору и соберите из них массив структур. В структуру включите идентификатор строки, чтобы по возвращении результата найти те же строки.

Нужно ли очищать временное хранилище после использования?

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

Почему после серверного вызова документ не считается изменённым?

Изменения реквизита Объект в серверной процедуре не всегда устанавливают признак модифицированности формы. Установите Модифицированность = Истина в конце серверной процедуры, чтобы платформа предложила записать документ при закрытии.

Итог

Что важно запомнить

Для формы объекта передача не нужна: вызывайте контекстную серверную процедуру и работайте с Объект.ИмяТабличнойЧасти. Для общих модулей и независимых таблиц используйте массив структур с минимальным набором полей или выгрузку во временное хранилище. Таблицу значений и ДанныеФормыКоллекция параметром передать нельзя.