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

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

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

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

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

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

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

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

В управляемой форме табличная часть хранится как реквизит формы типа «ДанныеФормыКоллекция», а её строка — «ДанныеФормыЭлементКоллекции». Эти типы существуют только в контексте формы и не сериализуются при вызове сервера. Попытка написать что-то вроде ОбработатьСтрокуНаСервере(Элементы.Товары.ТекущиеДанные) приведёт к ошибке «Ошибка передачи данных между клиентом и сервером» или «Недопустимое значение параметра».

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

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

Способ 1. Передать всю таблицу через ДанныеФормыВЗначение

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

&НаКлиенте

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

ПересчитатьНаСервере();

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

&НаСервере

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

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

Для Каждого СтрокаТовара Из ТаблицаТоваров Цикл

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

КонецЦикла;

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

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

Если табличная часть принадлежит объекту формы (документу, справочнику), метод РеквизитФормыВЗначение("Объект") вернёт объект конфигурации, и его табличная часть будет обычной коллекцией. После изменений объект нужно вернуть в форму через ЗначениеВРеквизитФормы либо, как в примере, перезаписать табличную часть.

Минус подхода — на сервер уходит вся таблица целиком, даже если изменилась одна ячейка. На больших табличных частях (сотни и тысячи строк) это заметно увеличивает трафик и время вызова, особенно при работе через веб-клиент или медленное соединение.

Способ 2. Передать одну строку через структуру

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

&НаКлиенте

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

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

Если ТекущиеДанные = Неопределено Тогда

Возврат;

КонецЕсли;

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

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

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

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

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

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

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

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

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

Запрос = Новый Запрос(

"ВЫБРАТЬ Цена ИЗ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, Номенклатура = &Номенклатура)");

Запрос.УстановитьПараметр("Номенклатура", ДанныеСтроки.Номенклатура);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

Результат.Цена = Выборка.Цена;

КонецЕсли;

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

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

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

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

Способ 3. Вызов серверного метода объекта

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

&НаСервере

Процедура ЗаполнитьЦеныНаСервере()

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

ДокументОбъект.ЗаполнитьЦеныПоВидуЦен(); // метод в модуле объекта

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

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

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

Сравнение вариантов

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

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

РеквизитФормыВЗначение (вся таблица)

Подходит, когда нужны все строки или связанные расчёты. Ограничение — передаётся весь объект, тяжело на больших таблицах.

Метод модуля объекта

Подходит для бизнес-логики документа, переиспользуется в проведении и обменах. Ограничение — требует преобразования формы в объект и обратно.

Как выбрать способ под свою задачу

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

Маршрут решения

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

Изменилась одна ячейка, нужно дозаполнить несколько полей строкиСоберите поля в структуру и вызовите серверную функцию без контекста
Нужно пересчитать все строки или итоги документаИспользуйте РеквизитФормыВЗначение и обработайте таблицу на сервере
Логика относится к документу и нужна при проведении или в обменахВынесите её в модуль объекта и вызывайте через преобразование формы
Табличная часть содержит сотни строк и вызовы частыеИзбегайте полной передачи таблицы, агрегируйте вызовы или переносите обработку на момент записи

Отдельно учитывайте режим работы пользователей. В тонком и веб-клиенте каждый серверный вызов — это сетевой обмен, поэтому не стоит делать вызов на каждое нажатие клавиши. Разумный приём — реагировать на событие «ПриИзменении» конкретного поля, а не «ПриАктивизацииСтроки», и по возможности объединять несколько действий в один вызов.

Типичные ошибки и как их избежать

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

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

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

Как проверить, что данные переданы корректно

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

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

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

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

Содержимое структуры в отладчике на сервере
Норма

Все поля присутствуют, типы совпадают с ожидаемыми, ссылки — это ссылки

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

Полей нет, значения Неопределено, вместо ссылки пришла строка

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

Обработчик завершается молча, ошибок нет

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

Ошибка обращения к полям Неопределено

Признак модифицированности после изменения строки
Норма

Звёздочка в заголовке формы, при закрытии предлагается сохранить

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

Форма закрывается без вопроса, изменения теряются

Ограничения и нюансы платформы

В структуру можно вкладывать примитивные типы, ссылки, даты, массивы, вложенные структуры и соответствия — всё это сериализуется без проблем. Нельзя передавать объекты типа «Запрос», «ТабличныйДокумент», «ДанныеФормы...» и другие несериализуемые типы. Если нужно передать список значений из строки (например, отобранные характеристики), используйте массив структур.

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

Итог

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

Строка табличной части не сериализуется и не передаётся на сервер напрямую. Для одной строки собирайте поля в структуру и вызывайте серверную функцию без контекста; для всей таблицы или логики документа — преобразуйте форму в объект. Всегда проверяйте ТекущиеДанные на Неопределено и не забывайте про признак модифицированности.

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

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

Нет. Тип «ДанныеФормыЭлементКоллекции» существует только в контексте управляемой формы и не сериализуется. Любой рабочий способ сводится к преобразованию: либо в структуру с нужными полями, либо в таблицу значений через РеквизитФормыВЗначение.

Что быстрее: структура или РеквизитФормыВЗначение?

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

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

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

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

Если серверная процедура изменила данные через ЗначениеВРеквизитФормы, форма обновится автоматически. Если вы меняете строку на клиенте по возвращённой структуре — проверьте, что ЗаполнитьЗначенияСвойств реально получило совпадающие имена полей, и при необходимости установите Модифицированность = Истина.

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

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

Что делать, если в строке есть поле с типом ХранилищеЗначения?

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