Какие значения переживут серверный вызов в управляемой форме 1С 8.3
Содержание
С сервера на клиент в 1С 8.3 передаются только значения, тип которых одновременно доступен на клиенте и сериализуется: примитивы (Число, Строка, Дата, Булево, Неопределено, Null), ссылки, УникальныйИдентификатор, Массив, Структура, Соответствие, СписокЗначений, ДвоичныеДанные, ТабличныйДокумент и данные формы. ТаблицаЗначений, ДеревоЗначений, Запрос, РезультатЗапроса, объекты справочников и документов, наборы записей и объекты метаданных на клиент не попадут.
Типичная ситуация: функция с &НаСервере возвращает выгрузку запроса, а клиент получает ошибку вызова. Лечится это не настройкой, а сменой типа: таблицу превращают в массив структур или в реквизит формы, объект — в данные формы, метаданные — в строку.
Общее правило передачи данных между сервером и клиентом
Любой серверный вызов из клиентского кода — это сериализация. Платформа упаковывает параметры, отправляет их на сервер, выполняет метод и упаковывает обратно результат. Если хотя бы одно значение внутри не упаковывается, падает весь вызов.
Тип годится для передачи, если выполняются два условия:
- ✅ в Синтакс-помощнике в разделе «Доступность» у типа указан тонкий клиент (и веб-клиент, если он у вас используется);
- ✅ тип сериализуемый — то есть его можно записать в XML и прочитать обратно.
Правило работает рекурсивно. Массив передаётся, но массив, в котором лежит ТаблицаЗначений, — уже нет. То же со Структурой и Соответствием: проверяется каждое вложенное значение.
Передача идёт в трёх местах:
- Параметры и возвращаемое значение методов с директивами
&НаСервереи&НаСервереБезКонтекста, вызванных с клиента. - Реквизиты формы — при вызове
&НаСервереони уходят на сервер и возвращаются целиком. - Параметры открываемой формы (
ОткрытьФормусо структурой параметров) и общие модули с признаком «Вызов сервера».
&НаСервереБезКонтекста не тащит на сервер реквизиты формы. Если методу нужна только ссылка и пара чисел, эта директива в разы легче по трафику, чем &НаСервере.
Примитивные типы, строки и даты
Простые значения проходят без оговорок:
| Тип | Пример значения | Замечание |
|---|---|---|
Число | 150.25 | точность сохраняется |
Строка | "ИНН 7701234567" | длинные строки тоже, но это трафик |
Дата | '20260107000000' | время передаётся вместе с датой |
Булево | Истина | — |
Неопределено | Неопределено | удобно как «нет результата» |
Null | Null | приходит из запросов; на клиенте сравнивайте через = Null |
Строка — самый частый способ протащить на клиент то, что иначе не проходит. Например, полное имя объекта метаданных или адрес во временном хранилище: оба значения — обычные строки.
Строки в сотни килобайт (сериализованные XML, JSON, Base64) гоняются при каждом вызове туда и обратно, если параметр объявлен без Знач. Такие данные кладите во временное хранилище, а на клиент отдавайте адрес.
Ссылки, перечисления и уникальные идентификаторы
Ссылочные значения передаются полностью: СправочникСсылка.*, ДокументСсылка.*, ПеречислениеСсылка.*, ПланВидовХарактеристикСсылка.*, ПланСчетовСсылка.*, ПланОбменаСсылка.*, БизнесПроцессСсылка.*, ЗадачаСсылка.*. Сюда же относятся ключи записей регистров и УникальныйИдентификатор.
Подвох в другом. Ссылка на клиенте — это только идентификатор плюс представление. Прочитать через точку реквизит объекта (Объект.Контрагент.ИНН) в клиентском коде нельзя: в тонком клиенте нет доступа к базе. Реквизит получают серверной функцией:
&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
ИНН = ИННКонтрагента(Объект.Контрагент);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ИННКонтрагента(Знач Контрагент)
Возврат Контрагент.ИНН;
КонецФункции
В конфигурациях на БСП вместо своей функции обычно берут ОбщегоНазначения.ЗначениеРеквизитаОбъекта или ЗначенияРеквизитовОбъекта — последняя возвращает Структуру сразу с несколькими полями за один вызов.
С перечислениями своя история. Менеджер Перечисления.ВидыОперацийПоступление на клиенте недоступен, а вот само значение перечисления — доступно. Для сравнения в клиентском коде используйте ПредопределенноеЗначение:
&НаКлиенте
Процедура ОбновитьВидимость()
ЭтоТовары = (Объект.ВидОперации =
ПредопределенноеЗначение("Перечисление.ВидыОперацийПоступление.Товары"));
Элементы.Склад.Видимость = ЭтоТовары;
КонецПроцедуры
Имя перечисления в примере условное — подставьте своё. Так же работает с предопределёнными элементами справочников и планов счетов.
Массивы, структуры и соответствия на клиенте
Универсальные коллекции — основной транспорт между контекстами:
- 📦
МассивиФиксированныйМассив; - 📦
СтруктураиФиксированнаяСтруктура; - 📦
СоответствиеиФиксированноеСоответствие; - 📦
СписокЗначений— с пометками, картинками и представлениями.
Ключ Структуры — строка по правилам имени переменной. Ключом Соответствия может быть любое передаваемое значение, например ссылка на номенклатуру. Это удобно, когда клиенту нужна справочная таблица «товар → цена».
Фиксированные варианты полезны, когда коллекция лежит в параметрах формы или кэшируется в модуле с повторным использованием возвращаемых значений: случайно изменить её не получится.
Если параметр серверного метода объявлен без Знач, платформа после вызова возвращает его значение на клиент. Для массива на 10 000 элементов это лишний рейс в обратную сторону. Ставьте Знач, если метод не должен менять параметр.
Пример: вернуть несколько значений одним вызовом
&НаСервереБезКонтекста
Функция ДанныеДляШапки(Знач Документ)
Результат = Новый Структура;
Результат.Вставить("Сумма", Документ.СуммаДокумента);
Результат.Вставить("Контрагент", Документ.Контрагент);
Результат.Вставить("Проведен", Документ.Проведен);
Возврат Результат;
КонецФункции
Один вызов вместо трёх. На медленном канале разница видна сразу.
Таблица значений и наборы записей: как передать на клиент
ТаблицаЗначений и ДеревоЗначений на клиенте не существуют. Возврат выгрузки запроса из серверной функции, вызванной с клиента, заканчивается ошибкой. Наборы записей регистров (РегистрСведенийНаборЗаписей и другие) тоже живут только на сервере.
Есть три рабочих способа.
Способ 1. Реквизит формы
Создайте реквизит формы типа ТаблицаЗначений с нужными колонками. На клиенте он виден как ДанныеФормыКоллекция — по нему можно идти циклом, искать строки, выводить в таблицу на форме. Заполняют его на сервере:
&НаСервере
Процедура ЗаполнитьТоварыНаСервере()
Таблица = ПолучитьТаблицуТоваров(); // любая ТаблицаЗначений
ЗначениеВРеквизитФормы(Таблица, "ТаблицаТоваров");
КонецПроцедуры
Обратное преобразование — РеквизитФормыВЗначение("ТаблицаТоваров"). Для табличной части объекта подойдёт Объект.Товары.Загрузить(Таблица).
Способ 2. Массив структур
Когда таблица нужна в общем клиентском модуле, а не в форме, её раскладывают на массив структур:
&НаСервереБезКонтекста
Функция ОстаткиДляКлиента(Знач Склад)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.КоличествоОстаток КАК Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Склад", Склад);
Таблица = Запрос.Выполнить().Выгрузить();
Результат = Новый Массив;
Для Каждого СтрокаТаблицы Из Таблица Цикл
Результат.Добавить(Новый Структура("Номенклатура, Количество",
СтрокаТаблицы.Номенклатура, СтрокаТаблицы.Количество));
КонецЦикла;
Возврат Результат;
КонецФункции
Имя регистра условное. В БСП то же самое делает ОбщегоНазначения.ТаблицаЗначенийВМассив.
Способ 3. Не передавать вовсе
Часто клиенту не нужна вся таблица — нужна сумма, флаг «есть остатки» или первые пять строк. Посчитайте это на сервере и верните число или булево значение. Самый быстрый вызов — тот, в котором мало данных.
| Способ | Когда выбирать | Минусы |
|---|---|---|
| Реквизит формы | данные показываются на форме | ходит туда и обратно при каждом &НаСервере |
| Массив структур | данные нужны в клиентском модуле | ручная раскладка колонок |
| Итог на сервере | клиенту нужен вывод, а не строки | не подходит для интерактивной работы со строками |
Двоичные данные, табличный документ, типы и метаданные
Помимо коллекций, на клиент проходят специализированные типы:
- 🗂
ДвоичныеДанные— файлы, картинки, вложения; - 🗂
ХранилищеЗначения— передаётся, но распаковать его методомПолучить()можно только на сервере; - 🗂
ТабличныйДокументиТекстовыйДокумент— именно так печатные формы попадают на экран; - 🗂
ТипиОписаниеТипов— проверкаТипЗнч(Значение) = Тип("ДокументСсылка.РеализацияТоваровУслуг")работает и на клиенте; - 🗂
Цвет,Шрифт,Картинка,ФорматированнаяСтрока— для оформления.
С двоичными данными объёмом в мегабайты лучше работать через временное хранилище. Сервер кладёт данные и возвращает адрес-строку:
&НаСервере
Функция АдресФайлаНаСервере()
Данные = СформироватьВыгрузку(); // возвращает ДвоичныеДанные
Возврат ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
КонецФункции
На клиенте адрес передают в метод получения файла или в ПолучитьИзВременногоХранилища. Второй аргумент — уникальный идентификатор формы: хранилище очистится, когда форму закроют.
Объекты метаданных на клиенте недоступны: Метаданные.Документы.Поступление в клиентском коде не сработает. Передавайте строку ПолноеИмя() или синоним, а свойства метаданных читайте на сервере и возвращайте структурой.
Например, клиенту нужно знать, есть ли у документа табличная часть «Услуги». Серверная функция проверяет это по метаданным и возвращает Булево. Если таких проверок много и результат не меняется в течение сеанса, вынесите функцию в общий модуль с повторным использованием возвращаемых значений: повторный вызов с теми же параметрами не пойдёт на сервер.
Данные формы и параметры открываемой формы
Реквизиты управляемой формы на клиенте представлены особыми типами — данными формы. Их платформа передаёт сама, и именно через них клиент работает с объектами и таблицами:
| Тип реквизита на сервере | Что видит клиент | Как преобразовать на сервере |
|---|---|---|
ДокументОбъект.Х, СправочникОбъект.Х | ДанныеФормыСтруктура | ДанныеФормыВЗначение, ЗначениеВДанныеФормы |
ТаблицаЗначений, табличная часть | ДанныеФормыКоллекция | РеквизитФормыВЗначение, ЗначениеВРеквизитФормы |
ДеревоЗначений | ДанныеФормыДерево | те же методы формы |
ДинамическийСписок | строки списка по ключам | данные читаются запросом на сервере |
Данные формы можно передать параметром в серверную процедуру, даже в &НаСервереБезКонтекста. Например, отправить на сервер только табличную часть Объект.Товары, а не всю форму целиком.
У динамического списка на клиенте доступна текущая строка: Элементы.Список.ТекущиеДанные возвращает поля, которые выведены в колонки. Если нужного поля в колонках нет, его добавляют в список (можно скрытой колонкой) или читают серверной функцией по ссылке.
Параметры ОткрытьФорму
Параметры открываемой формы — это Структура, и на её содержимое действуют те же ограничения. Ссылку, массив ссылок, число или строку передать можно. Таблицу значений или объект — нельзя: форма откроется с ошибкой.
&НаКлиенте
Процедура ОткрытьПодбор(Команда)
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Склад", Объект.Склад);
ПараметрыФормы.Вставить("АдресТоваров", ПоместитьТоварыВХранилище());
ОткрытьФорму("Обработка.ПодборТоваров.Форма", ПараметрыФормы, ЭтотОбъект);
КонецПроцедуры
Имя обработки и функции условные. Приём с адресом временного хранилища здесь стандартный: открываемая форма в ПриСозданииНаСервере достаёт таблицу из хранилища и раскладывает её в свой реквизит. Сама таблица на клиенте не появляется ни разу.
Возврат значений из открытой формы через Закрыть(Результат) и обработчик ОписаниеОповещения подчиняется тем же правилам: результатом может быть массив ссылок или структура, но не таблица значений.
Какие типы нельзя передать с сервера на клиент
Эти типы чаще всего приводят к ошибке при вызове сервера:
| Тип | Почему не проходит | Чем заменить |
|---|---|---|
ТаблицаЗначений, ДеревоЗначений | нет на клиенте | реквизит формы, массив структур |
Запрос, РезультатЗапроса, выборка | работает с базой | выгрузка → массив |
СправочникОбъект, ДокументОбъект | серверный объект | реквизит формы Объект, ДанныеФормыВЗначение на сервере |
Справочники.Х, Документы.Х (менеджеры) | серверные | вызов серверной функции |
| наборы записей регистров | серверные | массив структур |
МенеджерВременныхТаблиц | живёт в сеансе сервера | держите на сервере, запрос выполняйте целиком там |
ОбъектМетаданных | нет на клиенте | ПолноеИмя() строкой |
СхемаКомпоновкиДанных | серверная | адрес во временном хранилище |
ОбъектXDTO, СериализаторXDTO | серверные | строка XML/JSON |
форма (ЭтаФорма) | не сериализуется | передайте нужные реквизиты |
Объект документа нельзя вернуть на клиент даже «на минутку», чтобы поменять поле и записать. Правильная схема: форма объекта хранит его в реквизите Объект, правка идёт через данные формы, а запись — на сервере через ДанныеФормыВЗначение или РеквизитФормыВЗначение("Объект").
Обратное направление подчиняется тем же правилам. Передать с клиента на сервер ОписаниеОповещения с модулем формы или саму форму не получится, а ДанныеФормыКоллекция или Структуру — можно.
Как найти, какое значение ломает вызов
- Откройте отладчик и остановитесь на строке
Возвратсерверной функции. - Посмотрите тип возвращаемого значения в табло, раскройте вложенные элементы коллекции.
- Найдите тип, у которого в Синтакс-помощнике нет клиентской доступности.
- Замените его по таблице выше и повторите вызов.
Если в структуре десятки ключей, поиск ускоряет временная проверка в цикле: на сервере пройдите по ключам и выведите ТипЗнч каждого значения через Сообщить.
Частые вопросы
Почему в толстом клиенте код работал, а в тонком падает?
ТаблицаЗначений и чтение реквизитов через точку там недоступны.Можно ли передать на клиент выборку из запроса, если она маленькая?
Передаётся ли ХранилищеЗначения?
Получить() получится только на сервере.