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

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

Как на клиенте получить реквизиты ссылки в 1С

Как на клиенте в 1С получить реквизиты ссылки: вызов сервера, общие модули, кэширование, БСП-функции. Примеры кода, типичные ошибки и FAQ.

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

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

Ниже разобраны все основные способы с рабочим кодом, ограничения каждого варианта, способы снизить нагрузку на сервер и типичные ошибки, которые приводят к падению производительности форм.

Почему на клиенте нельзя обратиться к реквизитам ссылки напрямую

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

Если в обычном приложении (толстый клиент) запись Контрагент.ИНН работала незаметно, то в управляемом приложении такая конструкция в клиентской процедуре либо вызовет ошибку компиляции (в директиве &НаКлиенте обращение к реквизитам ссылки недоступно), либо спровоцирует неявный серверный вызов на каждое обращение. Десять реквизитов — десять обращений к серверу, и форма начинает заметно «подвисать».

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

Способ 1. Вызов серверной функции общего модуля

Универсальный и самый контролируемый способ — создать общий модуль с признаками «Сервер» и «Вызов сервера» и вынести туда функцию получения реквизитов. Функция принимает ссылку и возвращает структуру — сериализуемый тип, который без проблем передаётся между сервером и клиентом.

// Общий модуль РаботаСоСсылкамиВызовСервера

// Флаги: Сервер = Истина, ВызовСервера = Истина, Клиент (обычное приложение) — по необходимости

Функция РеквизитыКонтрагента(Ссылка) Экспорт

Результат = Новый Структура("Наименование, ИНН, КПП");

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

"ВЫБРАТЬ

| Контрагенты.Наименование КАК Наименование,

| Контрагенты.ИНН КАК ИНН,

| Контрагенты.КПП КАК КПП

|ИЗ

| Справочник.Контрагенты КАК Контрагенты

|ГДЕ

| Контрагенты.Ссылка = &Ссылка");

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

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

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

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

КонецЕсли;

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

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

На клиенте вызов выглядит так:

&НаКлиенте

Процедура КонтрагентПриИзменении(Элемент)

Если Не ЗначениеЗаполнено(Контрагент) Тогда

Возврат;

КонецЕсли;

Реквизиты = РаботаСоСсылкамиВызовСервера.РеквизитыКонтрагента(Контрагент);

ИНН = Реквизиты.ИНН;

КПП = Реквизиты.КПП;

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

Обратите внимание: запрос предпочтительнее обращения через точку (Ссылка.ИНН) даже на сервере, если нужно несколько реквизитов — запрос забирает их одним обращением к СУБД и не поднимает в память весь объект.

Способ 2. Готовые функции БСП

Если конфигурация построена на Библиотеке стандартных подсистем (БСП), писать собственные функции не нужно — в общем модуле ОбщегоНазначения уже есть готовые: ЗначениеРеквизитаОбъекта и ЗначенияРеквизитовОбъекта. Они доступны на сервере, а вызывать их из клиентского кода можно через серверную процедуру формы или через обёртку в своём модуле с вызовом сервера.

// Серверный контекст (например, &НаСервере в форме)

Функция ПолучитьРеквизиты(Ссылка)

// Один реквизит

ИНН = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИНН");

// Несколько реквизитов одним вызовом

Реквизиты = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(

Ссылка, "Наименование, ИНН, КПП");

Возврат Реквизиты;

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

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

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

Свой общий модуль с вызовом сервера

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

Функции БСП ЗначенияРеквизитовОбъекта

Готовое решение без своего кода, корректно обрабатывает пустые ссылки. Подходит только при наличии БСП.

Реквизит формы с данными объекта

Без серверных вызовов в момент работы: данные читаются при открытии. Не подходит для ссылок, выбранных пользователем на лету.

Дополнительные данные в поле ввода

Представление и часть данных подтягиваются платформой автоматически. Набор полей ограничен.

Способ 3. Реквизиты формы и чтение при открытии

Если реквизиты ссылки нужны постоянно в течение жизни формы (например, признаки поведения номенклатуры: «Это услуга», «Весовой товар»), эффективнее прочитать их один раз при создании формы на сервере и сохранить в реквизиты формы. Тогда клиентский код обращается к ним без каких-либо серверных вызовов.

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

Если ЗначениеЗаполнено(Объект.Номенклатура) Тогда

РеквизитыНоменклатуры = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(

Объект.Номенклатура, "ЭтоУслуга, ВесовойТовар");

ЭтоУслуга = РеквизитыНоменклатуры.ЭтоУслуга;

КонецЕсли;

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

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

Порядок действий для базового сценария
  1. 1
    Определите, какие именно реквизиты нужны клиенту — минимальный набор
  2. 2
    Создайте или найдите общий модуль с флагами Сервер и ВызовСервера
  3. 3
    Добавьте функцию, возвращающую структуру с реквизитами (запросом или через БСП)
  4. 4
    В клиентском обработчике проверьте заполненность ссылки, вызовите функцию и используйте результат
  5. 5
    Проверьте форму: нет повторных вызовов сервера в циклах и при каждом обращении

Как снизить нагрузку: кэширование и пакетные вызовы

Главная проблема серверных вызовов с клиента — их стоимость. Каждый вызов — это сетевой обмен, поэтому важно минимизировать их количество. Базовые приёмы: забирать все нужные реквизиты одной структурой вместо нескольких вызовов по одному реквизиту, не вызывать сервер внутри цикла по строкам табличной части и кэшировать результаты.

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

&НаКлиенте

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

Если КэшРеквизитов = Неопределено Тогда

КэшРеквизитов = Новый Соответствие;

КонецЕсли;

Данные = КэшРеквизитов.Получить(Объект.Номенклатура);

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

Данные = РаботаСоСсылкамиВызовСервера.РеквизитыНоменклатуры(Объект.Номенклатура);

КэшРеквизитов.Вставить(Объект.Номенклатура, Данные);

КонецЕсли;

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

Для массовой обработки (например, заполнение колонки в табличной части) правильнее собрать все ссылки в массив, передать его на сервер одним вызовом и вернуть соответствие «ссылка → структура реквизитов». Это один серверный вызов вместо десятков.

Что можно получить без серверного вызова

Часть информации о ссылке доступна на клиенте напрямую, и сервер дёргать не нужно. К таким данным относятся: уникальный идентификатор ссылки (Ссылка.УникальныйИдентификатор()), проверка на пустую ссылку через ЗначениеЗаполнено(), сравнение ссылок и получение представления, которое платформа уже показывает в поле ввода.

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

Типичные ошибки
01
Обращение Ссылка.Реквизит в клиентской процедуре — ошибка компиляции или неявные серверные вызовы
02
Возврат из серверной функции несериализуемых типов (СправочникОбъект, РезультатЗапроса) — исключение при передаче на клиент
03
Отдельный вызов сервера на каждый реквизит вместо одной структуры — многократный рост сетевых обращений
04
Забытые флаги Сервер и ВызовСервера у общего модуля — функция недоступна из клиентского кода
05
Отсутствие проверки пустой ссылки перед вызовом — лишний запрос к базе или пустой результат

Проверка результата и отладка

После внедрения кода стоит проверить два аспекта: корректность данных и количество серверных вызовов. Корректность проверяется просто — выведите полученную структуру через Сообщить() или посмотрите значения в отладчике в точке после вызова. Убедитесь, что для пустой ссылки и для несуществующего объекта (битая ссылка) функция ведёт себя предсказуемо.

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

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

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

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

Один серверный вызов, поля формы заполняются сразу

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

Форма подвисает, вызовов несколько

Пустая ссылка
Норма

Функция возвращает Неопределено или пустую структуру без ошибки

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

Исключение или запрос к базе с пустым параметром

Передача результата на клиент
Норма

Возвращается структура, соответствие или массив простых типов

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

Ошибка сериализации при возврате объекта

FAQ

Можно ли на клиенте выполнить запрос к базе?

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

Чем структура лучше возврата объекта справочника?

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

Как получить реквизиты сразу для списка ссылок?

Соберите ссылки в массив, передайте его в серверную функцию, выполните запрос с условием «Ссылка В (&МассивСсылок)» и верните соответствие, где ключ — ссылка, а значение — структура реквизитов. Это один серверный вызов вместо вызова на каждую ссылку.

Почему функция общего модуля не видна из клиентского кода?

Проверьте свойства общего модуля: должны быть установлены флаги «Сервер» и «Вызов сервера». Если модуль серверный без вызова сервера, его экспортные процедуры недоступны из клиентского контекста. Также у функции должно стоять ключевое слово «Экспорт».

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

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

Итог

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

Реквизиты ссылки на клиенте получают только через сервер: своя функция в общем модуле с вызовом сервера или готовые ЗначенияРеквизитовОбъекта из БСП. Возвращайте структуру, забирайте все поля одним вызовом, кэшируйте результат и никогда не вызывайте сервер в циклах.