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