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