Как обратиться к реквизиту связанного справочника на клиенте в управляемой форме 1С

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

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

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

Выясняем причину: почему возникает ошибка на клиенте?

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

Физически всей таблицы базы данных со всеми ее колонками (реквизитами) на клиенте нет. Попытка обратиться к реквизиту ДатаРегистрации через точку от ссылки Контрагент требует неявного обращения к серверу и выполнения запроса к базе данных. Чтобы разработчики не создавали тяжелые неоптимизированные интерфейсы, которые зависают при каждом действии пользователя, платформа 1С на корню блокирует такие обращения на клиенте. Именно поэтому генерируется исключение «Поле объекта не обнаружено».

Рассмотрим по шагам, какими способами можно обойти это ограничение правильно и эффективно.

Способ 1. Использование функций общего модуля БСП

Если вы работаете в современной типовой конфигурации (например, «Бухгалтерия предприятия 3.0», «Управление нашей фирмой» или «ERP Управление предприятием»), в ней гарантированно присутствует Библиотека стандартных подсистем (БСП). В составе БСП есть крайне полезный общий модуль ОбщегоНазначения, функции которого специально адаптированы для работы как на сервере, так и на клиенте.

Для решения нашей задачи идеально подходит функция ЗначениеРеквизитаОбъекта. Данный модуль имеет свойство «Вызов сервера», что позволяет вызывать его функции напрямую из клиентского контекста.

Рассмотрим пример кода на клиенте:


&НаКлиенте
Процедура ПолучитьДанныеКонтрагентаНажатие(Команда)
    
    СсылкаНаКонтрагента = Объект.Контрагент;
    
    Если ЗначениеЗаполнено(СсылкаНаКонтрагента) Тогда
        // Вызываем функцию БСП напрямую с клиента
        ДатаРегистрации = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаКонтрагента, "ДатаРегистрации");
        
        ПоказатьПредупреждение(, "Дата регистрации контрагента: " + Формат(ДатаРегистрации, "ДФ=dd.MM.yyyy"));
    Иначе
        ПоказатьПредупреждение(, "Сначала выберите контрагента!");
    КонецЕсли;
    
КонецПроцедуры

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


&НаКлиенте
Процедура ПолучитьНесколькоРеквизитовНажатие(Команда)
    
    СсылкаНаКонтрагента = Объект.Контрагент;
    
    Если ЗначениеЗаполнено(СсылкаНаКонтрагента) Тогда
        // Формируем список запрашиваемых реквизитов через запятую
        СтрокаРеквизитов = "ДатаРегистрации, ИНН, КПП";
        СтруктураДанных = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(СсылкаНаКонтрагента, СтрокаРеквизитов);
        
        // Доступ к полученным свойствам
        ТекстСообщения = СтрШаблон("ИНН: %1, Дата регистрации: %2", 
            СтруктураДанных.ИНН, 
            Формат(СтруктураДанных.ДатаРегистрации, "ДФ=dd.MM.yyyy"));
            
        ПоказатьПредупреждение(, ТекстСообщения);
    КонецЕсли;
    
КонецПроцедуры

Способ 2. Собственная серверная функция без контекста

Если по какой-то причине БСП в вашей конфигурации отсутствует, либо вы хотите жестко контролировать серверные вызовы, отличным решением будет написание собственного серверного метода в модуле формы. При этом критически важно использовать директиву компиляции &НаСервереБезКонтекста.

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

Реализуем этот метод на практике:


&НаКлиенте
Процедура ИмяКомандыНажатие(Команда)
    
    Если ЗначениеЗаполнено(Объект.Контрагент) Тогда
        // Передаем на сервер только легкую ссылку
        ДатаРегистрации = ПолучитьДатуРегистрацииНаСервере(Объект.Контрагент);
        
        ПоказатьПредупреждение(, "Дата регистрации из базы данных: " + ДатаРегистрации);
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьДатуРегистрацииНаСервере(СсылкаНаКонтрагента)
    
    // В контексте сервера обращение "через точку" полностью разрешено
    Возврат СсылкаНаКонтрагента.ДатаРегистрации;
    
КонецФункции

Способ 3. Вывод реквизита на форму без написания кода

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

Разберем этот процесс по шагам:

  1. Откройте конфигуратор и перейдите в редактор управляемой формы вашего документа (например, Реализация товаров и услуг).
  2. В верхнем правом углу перейдите на вкладку Реквизиты.
  3. Найдите основной реквизит формы Объект и раскройте его структуру (нажмите на плюс).
  4. Внутри объекта найдите реквизит Контрагент и также раскройте его. Перед вами появится список всех доступных реквизитов справочника «Контрагенты».
  5. Найдите реквизит ДатаРегистрации и с помощью мыши перетащите его в левое окно — в дерево Элементы формы.
  6. Платформа автоматически создаст поле формы, связав его с путем к данным Объект.Контрагент.ДатаРегистрации.
  7. Если вам не нужно показывать это поле пользователю, выделите созданный элемент формы, зайдите в его свойства и снимите флаг Видимость (или установите программно в ложь).

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


&НаКлиенте
Процедура ПроверитьДатуБезСервера(Команда)
    
    // Ошибки не будет! Платформа уже доставила это значение на клиент
    Если Объект.Контрагент.ДатаРегистрации < ТекущаяДата() Тогда
        // Ваш код валидации
    КонецЕсли;
    
КонецПроцедуры

Этот способ незаменим, когда реквизиты связанного объекта постоянно требуются в различных клиентских процедурах для интерактивных проверок «на лету».

← На главную