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