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

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

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

Разбираем способы передачи строки табличной части с клиента на сервер в 1С 8.3: через ДанныеФормыКоллекция, структуру и ЗначениеВСтрокуВнутр. Примеры кода и ошибки.

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

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

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

Почему строку нельзя передать напрямую

В управляемой форме табличная часть хранится как реквизит формы типа ДанныеФормыКоллекция, а её строка — ДанныеФормыЭлементКоллекции. Эти типы существуют только внутри формы и привязаны к её контексту. При вызове серверной процедуры без контекста формы передаваемые параметры сериализуются, и платформа отклоняет любые несериализуемые значения.

То же ограничение касается и обратного направления: серверная функция не может вернуть строку табличной части. Вернуть можно структуру, массив, таблицу значений (в пределах разумного объёма) или строку внутреннего представления через ЗначениеВСтрокуВнутр.

Способ 1: передать строку как структуру

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

&НаКлиенте

Процедура ТоварыПриИзменении(Элемент)

ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;

Если ТекущаяСтрока = Неопределено Тогда

Возврат;

КонецЕсли;

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

ДанныеСтроки.Вставить("Номенклатура", ТекущаяСтрока.Номенклатура);

ДанныеСтроки.Вставить("Количество", ТекущаяСтрока.Количество);

ДанныеСтроки.Вставить("Цена", ТекущаяСтрока.Цена);

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

ЗаполнитьЗначенияСвойств(ТекущаяСтрока, Результат);

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

&НаСервереБезКонтекста

Функция ПересчитатьНаСервере(ДанныеСтроки)

Результат = Новый Структура("Сумма, СтавкаНДС");

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

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

Возврат Результат;

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

Обратите внимание на обратный путь: серверная функция возвращает структуру с рассчитанными значениями, а клиентская процедура переносит их в строку через ЗаполнитьЗначенияСвойств. Это стандартный паттерн «структура туда — структура обратно».

Ограничение способа — ручное перечисление колонок. Если колонок много или их состав меняется, код придётся поддерживать. Для типовых сценариев с 3–7 полями это оптимальный вариант по скорости и читаемости.

Порядок действий при передаче через структуру
  1. 1
    Получите текущие данные строки через Элементы.ИмяТаблицы.ТекущиеДанные
  2. 2
    Соберите структуру с нужными колонками
  3. 3
    Вызовите серверную функцию, передав структуру параметром
  4. 4
    Верните из функции структуру с результатом
  5. 5
    Перенесите результат в строку через ЗаполнитьЗначенияСвойств

Способ 2: контекстный серверный вызов формы

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

&НаКлиенте

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

ПересчитатьНаСервере(Элементы.Товары.ТекущаяСтрока);

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

&НаСервере

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

ДокументОбъект = РеквизитФормыВЗначение("Объект");

СтрокаТовары = ДокументОбъект.Товары.НайтиПоИдентификатору(ИдентификаторСтроки);

Если СтрокаТовары <> Неопределено Тогда

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

КонецЕсли;

ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");

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

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

Сравнение способов передачи

Структура с полями строки

Быстро и дёшево, подходит для пересчёта одной строки. Минус — колонки перечисляются вручную.

Идентификатор строки + контекстный вызов

Подходит, когда нужен весь объект на сервере. Минус — дорогие РеквизитФормыВЗначение/ЗначениеВРеквизитФормы.

ВыгрузитьКолонки / Выгрузить в таблицу значений

Подходит для пакетной обработки нескольких строк. Минус — передаётся больше данных, чем нужно для одной строки.

ЗначениеВСтрокуВнутр

Универсально, но строка нечитаема и зависит от версии платформы. Использовать как крайний вариант.

Способ 3: передать таблицу значений

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

&НаКлиенте

Процедура ОбработатьВыделенные(Команда)

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

Для Каждого Ид Из Элементы.Товары.ВыделенныеСтроки Цикл

СтрокаДанных = Объект.Товары.НайтиПоИдентификатору(Ид);

Стр = Новый Структура("Номенклатура,Количество");

ЗаполнитьЗначенияСвойств(Стр, СтрокаДанных);

МассивСтрок.Добавить(Стр);

КонецЦикла;

ОбработатьНаСервере(МассивСтрок);

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

&НаСервереБезКонтекста

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

Для Каждого Стр Из МассивСтрок Цикл

// серверная обработка каждой строки

КонецЦикла;

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

Массив структур часто удобнее таблицы значений: не нужно описывать колонки и типы. Таблица значений оправдана, когда на сервере по ней строится запрос с временной таблицей.

Способ 4: ЗначениеВСтрокуВнутр

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

Частые ошибки и как их проверить

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

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

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

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

Вызов серверной процедуры
Норма

Нет ошибки сериализации, параметры доходят

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

Ошибка 'Значение недопустимого типа'

Данные на сервере
Норма

В отладчике структура содержит все нужные поля с верными значениями

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

Поля пустые или отсутствуют в структуре

Строка после вызова
Норма

Рассчитанные поля строки обновились в форме

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

Строка осталась без изменений

Производительность
Норма

Вызов одной строки выполняется без заметной паузы

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

Заметная задержка при каждом изменении строки

Что выбрать в типовых сценариях

Для пересчёта суммы в строке при изменении количества или цены лучше всего подходит структура: минимум трафика, простой код. Для операций над документом целиком (заполнение по основанию, групповой пересчёт) — контекстный серверный вызов с РеквизитФормыВЗначение. Для обработки выделенных строк — массив структур или таблица значений.

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

Итог

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

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

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

Можно ли передать строку табличной части в функцию &НаСервереБезКонтекста?

Нет, тип ДанныеФормыЭлементКоллекции не сериализуется. Соберите из строки структуру с нужными полями и передайте её — это стандартное решение.

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

В процедуре &НаСервере доступны реквизиты формы, включая табличную часть объекта, и работают РеквизитФормыВЗначение/ЗначениеВРеквизитФормы. В процедуре без контекста формы недоступна — туда данные нужно передавать параметрами.

Как передать на сервер сразу несколько выделенных строк?

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

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

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

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

Да: в контекстной серверной процедуре она доступна как реквизит формы, либо можно собрать массив структур. Но передавать всю коллекцию ради одной строки нерационально — это лишний трафик между клиентом и сервером.

Работает ли Выгрузить() у табличной части на тонком клиенте?

На тонком клиенте выгрузка всей ДанныеФормыКоллекция в таблицу значений ограничена. Надёжный кросс-платформенный вариант — цикл по строкам со сбором массива структур.