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