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

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

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

Причины возникновения ошибки в тонком клиенте

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

  1. Ограничение на разыменование ссылок на стороне тонкого клиента. В тонком и веб-клиенте для объектов ссылочного типа (ссылки на справочники, документы, бизнес-процессы, задачи) доступны только базовые стандартные свойства (например, ссылка, строковое представление, пометка удаления). Доступ к произвольным реквизитам конфигурации через точку заблокирован платформой на уровне клиента. Любая попытка прочитать реквизит связанного объекта на клиенте приводит к ошибке «Поле объекта не обнаружено». В толстом клиенте это ограничение отсутствует, так как он имеет прямой кэш объектов базы данных.
  2. Опасность цепочек обращений через точку при незаполненных значениях. Даже на сервере конструкция с несколькими точками упадет с ошибкой, если промежуточный реквизит (например, БизнесПроцесс или ГлавнаяЗадача) не заполнен и содержит пустую ссылку или Неопределено. При обращении к реквизиту незаполненного поля платформа вернет Неопределено, а следующая точка вызовет исключение.
  3. Некорректная передача контекста формы. Передача всей формы целиком (ЭтотОбъект) с клиента на сервер является тяжелой операцией, приводящей к избыточной сериализации данных и потенциальным ошибкам доступа к свойствам.

Способ 1. Инициализация реквизитов в событии «ПриСозданииНаСервере»

Рассмотрим основной способ отображения данных на управляемой форме. Заполнение реквизитов формы или реквизитов объекта при открытии должно происходить на стороне сервера в момент создания формы. Это избавляет от лишних клиент-серверных вызовов при открытии формы.

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


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

Способ 2. Оптимальное чтение данных с помощью запроса

Рассмотрим наиболее производительный подход. Разыменование ссылок через точку на сервере приводит к считыванию всех полей ссылочного объекта целиком, что создает избыточную нагрузку на СУБД. Использование объекта Запрос позволяет считать исключительно нужное поле и безопасно обойти пустые значения через механизм соединений.

Разберем пример серверного кода с использованием запроса:


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

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

Если значение требуется получить динамически в процессе работы пользователя на клиенте (например, в обработчике события ПриИзменении поля формы), организуем вызов серверной функции. При этом передаем только саму ссылку, а не всю форму:


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

&НаСервереБезКонтекста
Функция ПолучитьСрокИсполнения(СсылкаНаБизнесПроцесс)
    
    Если Не ЗначениеЗаполнено(СсылкаНаБизнесПроцесс) Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    ГлавнаяЗадача = СсылкаНаБизнесПроцесс.ГлавнаяЗадача;
    Если ЗначениеЗаполнено(ГлавнаяЗадача) Тогда
        Возврат ГлавнаяЗадача.СрокИсполненияВхДок;
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

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

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


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

Способ 5. Перенос логики в модуль объекта («ОбработкаЗаполнения»)

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

Это обеспечит корректное заполнение данных как при интерактивном вводе на основании, так и при создании объекта программно без открытия формы:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    
    // Если объект заполняется на основании структуры или ссылки
    Если ТипЗнч(ДанныеЗаполнения) = Тип("БизнесПроцессСсылка.ИмяВашегоБизнесПроцесса") Тогда
        
        ЭтотОбъект.БизнесПроцесс = ДанныеЗаполнения;
        
        Если ЗначениеЗаполнено(ДанныеЗаполнения.ГлавнаяЗадача) Тогда
            ЭтотОбъект.СрокИсполненияВхДок = ДанныеЗаполнения.ГлавнаяЗадача.СрокИсполненияВхДок;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры
← На главную