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