Как получить значение реквизита через точку на клиенте в управляемых формах 1С?

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

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

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

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

База данных физически расположена на сервере. Обращение вида Объект.Машина.Водитель требует выполнения запроса к СУБД для чтения поля из таблицы справочника. Если бы платформа разрешала подобные операции на клиенте, происходили бы скрытые синхронные вызовы сервера по сети при каждом чтении поля, что приводило бы к зависаниям клиентского приложения. Поэтому разработчики платформы архитектурно заблокировали доступ к реквизитам ссылочных типов на клиенте.

Почему не следует использовать РеквизитФормыВЗначение

Нередко на форумах можно встретить рекомендацию вызвать функцию РеквизитФормыВЗначение. Рассмотрим, почему данный подход является грубой ошибкой проектирования в контексте получения отдельного реквизита:

  1. Метод РеквизитФормыВЗначение преобразует реквизит формы Объект в прикладной объект базы данных. Для этого на сервер передается весь контекст формы, выполняется полная сериализация и десериализация всех данных, создавая неоправданную нагрузку на оперативную память и сеть.
  2. Даже внутри полученного серверного объекта поле Машина останется ссылкой. Чтобы прочитать реквизит Водитель через объектную модель, пришлось бы вызывать ПолучитьОбъект() для машины, что инициирует считывание абсолютно всех реквизитов и табличных частей справочника автомобилей ради одного поля.

Посмотрим на практические и оптимизированные способы решения этой задачи.

Способ 1. Вызов внеконтекстной серверной функции с запросом

Разберем классический и наиболее надежный способ получения связанных данных. Для минимизации трафика между клиентом и сервером создадим отдельную функцию с директивой &НаСервереБезКонтекста. В нее передается только ссылка на выбранный автомобиль, а результат возвращается точечно с помощью объекта Запрос.

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


&НаКлиенте
Процедура аст_МашинаПриИзменении(Элемент)
    
    Если ЗначениеЗаполнено(Объект.аст_Машина) Тогда
        Объект.аст_Водитель = ПолучитьВодителяМашины(Объект.аст_Машина);
    Иначе
        Объект.аст_Водитель = ПредопределенноеЗначение("Справочник.ФизическиеЛица.ПустаяСсылка");
    КонецЕсли;

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

&НаСервереБезКонтекста
Функция ПолучитьВодителяМашины(СсылкаНаМашину)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Т.Водитель КАК Водитель
        |ИЗ
        |   Справочник.аст_Машины КАК Т
        |ГДЕ
        |   Т.Ссылка = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", СсылкаНаМашину);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Водитель;
    КонецЕсли;
    
    Возврат ПредопределенноеЗначение("Справочник.ФизическиеЛица.ПустаяСсылка");
    
КонецФункции

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

Способ 2. Использование функций Библиотеки Стандартных Подсистем (БСП)

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

Рассмотрим, как выглядит серверный вызов с использованием БСП:


&НаКлиенте
Процедура аст_МашинаПриИзменении(Элемент)
    
    Объект.аст_Водитель = ПолучитьВодителяМашиныБСП(Объект.аст_Машина);

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

&НаСервереБезКонтекста
Функция ПолучитьВодителяМашиныБСП(СсылкаНаМашину)
    
    Если Не ЗначениеЗаполнено(СсылкаНаМашину) Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаМашину, "Водитель");

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

Функция ОбщегоНазначения.ЗначениеРеквизитаОбъекта внутри себя выполняет быстрый параметризованный запрос с контролем прав доступа, гарантируя минимальные затраты вычислительных ресурсов платформы.

Способ 3. Отображение реквизита на форме без сохранения в объект

Проанализируем задачу со стороны структуры данных: действительно ли необходимо физически хранить реквизит аст_водитель в базе данных текущего документа или справочника? Если водитель всегда однозначно определяется машиной и вам требуется только отображать его на форме для пользователя, дублировать данные в реквизитах не нужно.

Разберем по шагам, как вывести реквизит ссылки на форму без единой строчки программного кода:

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

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

Способ 4. Передача составных данных из формы выбора

Рассмотрим еще одну оптимизацию, которая позволяет полностью избежать лишних серверных вызовов в момент выбора значения. Если выбор машины выполняется пользователем через форму списка справочника, мы можем настроить форму так, чтобы она возвращала на клиент не просто ссылку, а структуру данных с уже прочитанными реквизитами.

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

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

← На главную