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

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

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

Как на клиенте в 1С получить значение справочника: чтение реквизитов через ссылку, серверные вызовы, кэширование, типичные ошибки и примеры кода на встроенном языке.

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

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

Ниже разобраны основные способы получения значений справочника на клиенте: чтение реквизитов по ссылке, серверные вызовы, кэширование, работа с предопределёнными элементами и типичные ошибки, которые приводят к лишним обращениям к базе.

Как устроено обращение к данным справочника на клиенте

В управляемом приложении код с директивой &НаКлиенте выполняется вне контекста базы данных. Тем не менее ссылка на элемент справочника — это полноценный объект, и платформа позволяет обратиться к его реквизитам через точку. При этом под капотом выполняется неявный серверный вызов: платформа запрашивает значение реквизита из базы и возвращает его в клиентский код.

Это удобно для одиночных обращений, но опасно в циклах: каждое обращение Строка.Товар.Артикул внутри перебора табличной части — отдельный обмен с сервером. На медленном канале форма начинает заметно «подтормаживать».

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

Получение значения реквизита через точку

Самый простой способ — прямое обращение через точку к реквизиту ссылки:

&НаКлиенте

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

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

Ставка = Объект.Товар.СтавкаНДС;

Наименование = Объект.Товар.Наименование;

КонецЕсли;

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

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

Отдельный нюанс — обращение через точку к «длинной» цепочке вида Объект.Контрагент.Договор.Валюта. Каждый шаг цепочки — потенциальное чтение из базы. Такие конструкции на клиенте лучше не использовать вообще.

Серверная функция: получить несколько реквизитов одним вызовом

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

Вариант с серверной процедурой в модуле формы:

&НаКлиенте

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

ДанныеТовара = ПолучитьДанныеТовара(Объект.Товар);

Объект.СтавкаНДС = ДанныеТовара.СтавкаНДС;

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

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

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

Возврат ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ТоварСсылка, "СтавкаНДС,ЕдиницаИзмерения");

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

Функция ОбщегоНазначения.ЗначенияРеквизитовОбъекта есть в библиотеке стандартных подсистем и в большинстве типовых конфигураций. Если её нет, аналог пишется запросом к таблице справочника: ВЫБРАТЬ СтавкаНДС, ЕдиницаИзмерения ИЗ Справочник.Номенклатура ГДЕ Ссылка = &Ссылка.

Порядок действий для серверного чтения
  1. 1
    Определите, какие реквизиты справочника нужны на клиенте
  2. 2
    Создайте в форме серверную функцию без контекста или функцию в общем модуле с признаком «Сервер»
  3. 3
    Внутри функции получите значения реквизитов запросом или через ЗначенияРеквизитовОбъекта
  4. 4
    Верните результат структурой на клиент
  5. 5
    В клиентском обработчике вызовите функцию один раз и заполните поля формы

Общий модуль для таких функций должен иметь установленные флажки «Сервер» и «Вызов сервера», иначе клиентский код не сможет его вызвать. Функция должна возвращать только сериализуемые типы: структуры, массивы, примитивы, ссылки. Вернуть «объект» справочника (СправочникОбъект) на клиент нельзя.

Кэширование значений на клиенте

Если одни и те же данные справочника запрашиваются многократно — например, реквизиты текущей организации или склада по умолчанию — имеет смысл кэшировать их на время сеанса. Для этого в типовых конфигурациях используются модули с постфиксом «ВызовСервераПовтИсп» (повторное использование возвращаемых значений).

У общего модуля в свойстве «Повторное использование возвращаемых значений» выбирается «На время вызова» или «На время сеанса». Тогда повторный вызов функции с теми же параметрами не обращается к базе, а берёт результат из кэша платформы.

// Общий модуль ОбщегоНазначенияВызовСервераПовтИсп

Функция СтавкаНДСТовара(ТоварСсылка) Экспорт

Возврат ТоварСсылка.СтавкаНДС;

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

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

Предопределённые элементы и значения перечислений

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

&НаКлиенте

Процедура ПриОткрытии(Отказ)

// Вариант для тонкого клиента с глобальным контекстом

ПустаяНоменклатура = ПредопределенноеЗначение("Справочник.Номенклатура.ПустаяСсылка");

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

Функция ПредопределенноеЗначение работает на клиенте и позволяет получить пустые ссылки, значения перечислений и предопределённые элементы справочников без обращения к серверу. Это самый дешёвый способ, и его стоит предпочитать всегда, когда нужен именно предопределённый элемент или значение перечисления.

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

Тонкий, толстый и веб-клиент: различия

На толстом клиенте в обычном приложении ограничений практически нет: там доступен прямой запрос к базе и метод ПолучитьОбъект(). В управляемом приложении и на тонком/веб-клиенте картина другая: запросы и объекты недоступны, остаются только обращение через точку и серверные вызовы.

Сравнение способов

Обращение через точку

Подходит для 1–2 реквизитов при редком срабатывании. Ограничение: каждый реквизит — отдельный серверный вызов, опасно в циклах.

Серверная функция формы или общего модуля

Универсальный способ: все реквизиты за один вызов. Требует серверного контекста и возврата сериализуемых типов.

ПредопределенноеЗначение

Самый быстрый, без сервера вообще. Работает только для предопределённых элементов, перечислений и пустых ссылок.

Кэш повторного использования

Оптимален для редко меняющихся данных. Не подходит для часто редактируемых реквизитов.

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

Проверка результата и типичные ошибки

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

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

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

Количество серверных вызовов
Норма

Один вызов на обработчик изменения

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

Вызов на каждую строку таблицы — видно в замере производительности

Возвращаемое значение функции
Норма

Структура с заполненными полями

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

Неопределено или пустые значения при заполненной ссылке

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

Код проверяет ЗначениеЗаполнено и не обращается к серверу

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

Лишние вызовы и пустые данные в полях формы

Для диагностики лишних вызовов удобно использовать замер производительности в конфигураторе или технологический журнал с событием CALL. Если при изменении одного поля формы фиксируется десяток обращений к серверу — код чтения реквизитов нужно переписывать.

FAQ

Можно ли на клиенте получить табличную часть элемента справочника?

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

Почему на клиенте возникает ошибка «Метод объекта не обнаружен» при обращении к реквизиту?

Чаще всего переменная содержит не ссылку, а другой тип данных (строку, Неопределено) либо реквизит с таким именем отсутствует у справочника. Проверьте тип значения через ТипЗнч и состав реквизитов в конфигураторе.

Что быстрее: обращение через точку или запрос?

Для одного-двух реквизитов разница незаметна — оба варианта идут в базу. Запрос выигрывает, когда нужно несколько реквизитов сразу или данные по множеству ссылок: он получает всё за одно обращение к СУБД.

Как получить представление (наименование) справочника без серверного вызова?

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

Можно ли изменить реквизит справочника прямо из клиентского кода?

Нет. Изменение данных выполняется только на сервере: через ПолучитьОбъект(), установку реквизитов и Записать() в серверной процедуре. Клиент может только передать ссылку и новые значения параметрами.

Работает ли ПредопределенноеЗначение на мобильном клиенте?

Да, функция доступна на тонком, веб- и мобильном клиенте. Ограничение одно: получить так можно только предопределённые элементы, перечисления и пустые ссылки, обычные элементы справочника — нет.

Итог

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

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