Разработка и Конфигурация · 13 мин
Как передать табличную часть на сервер в 1С
Как передать табличную часть документа с клиента на сервер в 1С: выгрузка в массив структур, ДанныеФормыКоллекция, примеры кода, типичные ошибки и проверка результата.
В управляемом приложении 1С код формы делится на клиентский и серверный, и напрямую «протянуть» табличную часть документа в серверную процедуру нельзя — коллекция данных формы не сериализуется между контекстами автоматически. Разработчику нужно явно подготовить данные на клиенте, передать их в серверный вызов и там обработать. От правильного выбора способа зависят производительность, объём трафика и устойчивость кода к изменениям конфигурации.
Основных подхода три: выгрузка табличной части в массив структур, передача всей коллекции через ДанныеФормыКоллекция с преобразованием на сервере и работа с объектом целиком через реквизит формы типа ДанныеФормыСтруктура. Каждый вариант имеет свои условия применения, ограничения и подводные камни.
Ниже разобраны рабочие примеры кода для управляемых форм, критерии выбора способа, типичные ошибки и способы проверить, что данные дошли до сервера без потерь. Примеры ориентированы на типовой синтаксис платформы 8.3; имена объектов и реквизитов подставьте из своей конфигурации.
Почему табличную часть нельзя передать «как есть»
В управляемой форме табличная часть документа представлена реквизитом типа ДанныеФормыКоллекция. Это специальный объект платформы, привязанный к контексту формы. При вызове серверной процедуры с директивой &НаСервере контекст формы туда не передаётся: серверная процедура в модуле формы видит реквизиты формы только если вызывается из формы и форма пересоздаётся на сервере, а в общем модуле контекста формы нет вовсе.
Кроме того, платформа ограничивает типы, которые можно передавать между клиентом и сервером. Допустимы примитивные типы, структуры, массивы, соответствия, ссылки, таблицы значений (с ограничениями) и некоторые другие сериализуемые типы. ДанныеФормыКоллекция в этот список не входит как самостоятельное значение для передачи в общий серверный модуль.
Поэтому задача сводится к преобразованию: на клиенте или в серверном контексте формы данные превращают в сериализуемую структуру — массив структур или таблицу значений — и уже её передают дальше, например в серверный общий модуль для проведения расчётов или записи.
Способ 1. Выгрузка в массив структур на клиенте
Самый универсальный способ, когда серверная логика вынесена в общий модуль: на клиенте обходят строки табличной части и складывают нужные поля в массив структур. Массив структур свободно передаётся на сервер, а серверный код не зависит от контекста формы.
Пример клиентской процедуры:
&НаКлиенте
Процедура РассчитатьНаСервере(Команда)
МассивСтрок = Новый Массив;
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
СтруктураСтроки = Новый Структура;
СтруктураСтроки.Вставить("Номенклатура", СтрокаТЧ.Номенклатура);
СтруктураСтроки.Вставить("Количество", СтрокаТЧ.Количество);
СтруктураСтроки.Вставить("Цена", СтрокаТЧ.Цена);
МассивСтрок.Добавить(СтруктураСтроки);
КонецЦикла;
Результат = РассчитатьСуммыНаСервере(МассивСтрок);
КонецПроцедуры
Серверная функция в общем модуле (с признаком «Сервер») принимает массив и обрабатывает его как обычную коллекцию:
Функция РассчитатьСуммыНаСервере(МассивСтрок) Экспорт
ИтоговаяСумма = 0;
Для Каждого Строка Из МассивСтрок Цикл
ИтоговаяСумма = ИтоговаяСумма + Строка.Количество * Строка.Цена;
КонецЦикла;
Возврат ИтоговаяСумма;
КонецФункции
Плюс подхода — полный контроль над составом передаваемых полей и независимость от формы. Минус — ручное перечисление колонок: при добавлении новой колонки в табличную часть код выгрузки легко забыть обновить, и поле «молча» потеряется.
Способ 2. Преобразование ДанныеФормыКоллекция в таблицу значений на сервере
Если серверная обработка выполняется в модуле самой формы (директива &НаСервере), выгружать данные на клиенте не нужно. В серверной процедуре формы доступен реквизит Объект, и табличную часть можно преобразовать в таблицу значений штатными средствами.
&НаСервере
Процедура ОбработатьТоварыНаСервере()
ТаблицаТоваров = Объект.Товары.Выгрузить();
Для Каждого СтрокаТЗ Из ТаблицаТоваров Цикл
// серверная обработка строки
КонецЦикла;
КонецПроцедуры
Метод Выгрузить() у коллекции данных формы возвращает таблицу значений со всеми колонками табличной части. Дальше таблицу значений можно передать в общий серверный модуль — этот тип сериализуется платформой без ограничений по составу колонок, если в колонках лежат допустимые типы.
Обратная загрузка выполняется методом Загрузить(): после серверной обработки таблицу значений можно вернуть в форму и перезаписать табличную часть. Это удобно для сценариев «заполнить по кнопке», «пересчитать всё», «подобрать товары».
&НаСервере
Процедура ЗагрузитьРезультат(ТаблицаРезультата)
Объект.Товары.Загрузить(ТаблицаРезультата);
КонецПроцедуры
- 1На клиенте вызовите серверную процедуру модуля формы (&НаСервере)
- 2В ней выполните Объект.Товары.Выгрузить() и получите таблицу значений
- 3Передайте таблицу в общий серверный модуль для расчётов
- 4Полученную таблицу загрузите обратно: Объект.Товары.Загрузить(Таблица)
- 5Убедитесь, что форма обновилась и пользователь видит изменённые строки
Способ 3. Работа с объектом целиком без передачи табличной части
Часто передавать табличную часть вообще не требуется. Если цель — записать документ, провести его или выполнить тяжёлую серверную обработку, правильнее перенести всю работу на сервер и оперировать объектом там. На клиенте остаётся только вызов серверной процедуры с минимальными параметрами — например, со ссылкой на документ.
Для нового объекта, данные которого ещё только в форме, используют преобразование реквизита формы в объект: РеквизитФормыВЗначение("Объект"). Полученный объект документа содержит табличную часть как обычную таблицу значений, с ним можно работать и записывать. После изменений объект возвращают в форму через ЗначениеВРеквизитФормы().
&НаСервере
Процедура ЗаписатьСОбработкойНаСервере()
ДокументОбъект = РеквизитФормыВЗначение("Объект");
Для Каждого СтрокаТЧ Из ДокументОбъект.Товары Цикл
СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
КонецЦикла;
ДокументОбъект.Записать();
ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
КонецПроцедуры
Этот подход снижает сетевой трафик: между клиентом и сервером не гоняются копии таблицы, а пересчёт и запись выполняются в одном серверном вызове. Для документов с сотнями строк разница в отклике формы заметна.
Сравнение способов и критерии выбора
Выбор зависит от того, где живёт серверная логика, каков объём данных и нужно ли возвращать результат в форму. Ориентируйтесь на следующие условия.
Сравнение вариантов
Подходит для небольших таблиц и логики в общих модулях. Ограничение: ручное перечисление полей, риск потерять новую колонку.
Оптимально для кнопок обработки в модуле формы: все колонки сохраняются автоматически. Ограничение: привязка к контексту формы.
Лучший вариант для записи и проведения документа целиком. Ограничение: тяжёлая операция, не подходит для частых вызовов.
Для уже записанных документов: сервер сам читает табличную часть из базы. Не работает с несохранёнными изменениями в форме.
| Критерий | Массив структур | Выгрузить() в форме | Объект целиком |
|---|---|---|---|
| Нужен общий серверный модуль | Да, напрямую | Через таблицу значений | Через объект или ссылку |
| Риск потери колонок | Высокий | Нет | Нет |
| Запись документа | Не предназначен | Не предназначен | Основной сценарий |
| Трафик клиент–сервер | Зависит от полей | Один серверный вызов | Минимальный |
Как выбрать действие
Типичные ошибки и как их избежать
Самая частая ошибка — попытка передать Объект.Товары параметром в функцию общего серверного модуля. Платформа выдаёт ошибку преобразования данных, потому что ДанныеФормыКоллекция не сериализуется вне контекста формы. Лечится преобразованием в таблицу значений или массив структур до вызова.
Вторая группа ошибок связана с директивами компиляции. Код, написанный в &НаКлиенте, не имеет доступа к запросам, менеджерам объектов и РеквизитФормыВЗначение. Обратная ситуация — попытка обратиться к элементам формы из &НаСервереБезКонтекста, где реквизит Объект недоступен. Проверяйте директивы до отладки логики.
Третья типичная проблема — потеря данных при обратной загрузке: Загрузить() полностью замещает табличную часть. Если серверная таблица не содержит часть колонок, соответствующие значения в форме будут очищены. Перед загрузкой убедитесь, что состав колонок совпадает, либо обновляйте строки по ключу вместо полной замены.
Проверка результата и ограничения
После внедрения проверьте передачу на контрольном примере: документ с двумя-тремя строками, где заранее известны значения каждого поля. Сравните данные на клиенте до вызова и внутри серверной процедуры через отладчик — точка останова в серверном коде покажет, дошёл ли массив или таблица полностью.
Учитывайте ограничение на отладку: чтобы видеть серверные вызовы, отладка должна быть включена и на сервере 1С (или используйте файловую базу, где клиент и сервер совмещены). Без этого точки останова в серверных процедурах просто не сработают, и проверка превратится в гадание.
Для больших табличных частей дополнительно замерьте время вызова. Если таблица содержит тысячи строк, передача массива структур может занимать заметное время — в таких случаях переходите на работу с объектом на сервере или передачу ссылки с чтением данных запросом.
Как проверить результат
Совпадает с числом строк табличной части в форме
Строк меньше — часть данных потеряна при выгрузке
Каждое поле в серверной таблице заполнено как в форме
Отдельные колонки пустые — поле не включено в структуру или не совпало имя
Все колонки табличной части сохранили значения
Часть колонок очистилась — Загрузить() получил неполную таблицу
Вызов выполняется без видимой задержки
Форма подвисает — нужен перенос обработки на сервер целиком
Частые вопросы
Можно ли передать табличную часть в процедуру &НаСервереБезКонтекста?
Напрямую нет — в такой процедуре недоступен реквизит Объект. Передайте данные параметром: массив структур, собранный на клиенте, или таблицу значений, подготовленную в контекстной серверной процедуре формы, которая уже вызовет метод без контекста.
Что быстрее: массив структур или таблица значений?
Для небольших объёмов разница незаметна, выбирайте по удобству кода. На больших таблицах таблица значений обычно предпочтительнее: она компактнее при сериализации и удобнее для серверной обработки запросами и свёртками.
Как передать табличную часть внешней обработки на сервер?
Принципы те же: в форме обработки используйте серверную процедуру с Выгрузить() либо собирайте массив структур на клиенте и передавайте в серверный метод модуля обработки. Отличие только в том, что у формы обработки реквизит с данными может называться иначе, чем Объект.
Почему после Загрузить() пропали значения части колонок?
Метод Загрузить() полностью замещает коллекцию: колонки, отсутствующие в загружаемой таблице значений, очищаются. Проверьте состав колонок серверной таблицы или замените полную загрузку на построчное обновление по номеру строки или ключевому полю.
Можно ли изменить табличную часть на сервере без возврата в форму?
Да, если документ уже записан: получите объект по ссылке в серверном модуле, измените табличную часть и вызовите Записать(). Но учтите, что открытая у пользователя форма покажет старые данные, пока её не обновят или не перечитают.
Передаётся ли табличная часть при обычном вызове &НаСервере в модуле формы?
Формально данные формы доступны в серверной процедуре модуля формы, потому что платформа пересоздаёт контекст формы на сервере. Отдельно «передавать» табличную часть не нужно — работайте с Объект.Товары напрямую в этой процедуре.
Что важно запомнить
ДанныеФормыКоллекция напрямую на сервер не передаётся: преобразуйте её в массив структур на клиенте или в таблицу значений через Выгрузить() в серверной процедуре формы. Для записи и проведения работайте с объектом целиком через РеквизитФормыВЗначение. Проверяйте состав колонок при обратной загрузке и не делайте серверный вызов на каждое изменение строки.