В процессе разработки в среде 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда простая, на первый взгляд, операция получения объекта из ссылки завершается аварийно. Особенно часто это происходит при работе с типовыми конфигурациями (УТ 11, ERP 2, КА 2), использующими Библиотеку стандартных подсистем (БСП). Рассмотрим ситуацию, когда выполнение метода ПолучитьОбъект() вызывает ошибку: «При подписке ... на событие произошло ошибка. Обработчик события не найден».
Разберем типичный сценарий. Программист пытается программно обработать элементы справочника, например, присоединенные файлы номенклатуры. Код выглядит следующим образом:
&НаСервере
Процедура Тест()
ЭтоСсылка = Справочники.НоменклатураПрисоединенныеФайлы.НайтиПоНаименованию("2");
Если Не ЭтоСсылка.Пустая() Тогда
ЭтоОбъект = ЭтоСсылка.ПолучитьОбъект();
ЭтоОбъект.Удалить();
КонецЕсли;
КонецПроцедуры
Несмотря на то, что код написан верно, на строке с вызовом ПолучитьОбъект() система выдает ошибку о потере обработчика события. Почему это происходит именно в этот момент? Дело в том, что когда мы вызываем ПолучитьОбъект(), платформа 1С не просто считывает данные из базы, но и полностью инициализирует объект в оперативной памяти. В процессе этой инициализации система проверяет все зарегистрированные Подписки на события, которые относятся к данному типу объекта.
Если в метаданных существует подписка (например, на событие ПриКопировании или ПередЗаписью), платформа обязана подготовить связь с процедурой-обработчиком. Если модуль, в котором расположен этот обработчик, недоступен в текущем контексте исполнения, возникает рассматриваемая ошибка. Таким образом, проблема заключается не в отсутствии самого кода, а в видимости общего модуля для текущего сеанса.
Проанализируем контекст выполнения. Одной из наиболее частых причин является запуск системы в режиме Толстого клиента (управляемое приложение). В современных типовых конфигурациях, ориентированных на работу через Тонкий клиент и Веб-клиент, многие общие модули оптимизированы.
Для большинства серверных общих модулей в свойствах установлены флаги Сервер, Внешнее соединение и иногда Клиент (управляемое приложение). Однако флаг Толстый клиент (управляемое приложение) зачастую снят. Когда вы запускаете отладку в толстом клиенте, платформа пытается скомпилировать код обработчика подписки под этот контекст, не находит разрешения в свойствах модуля и сообщает, что обработчик не найден.
Если вы вызываете метод ПолучитьОбъект() в контексте, который требует обращения к серверному модулю, проверьте свойство Вызов сервера у того общего модуля, где расположен обработчик подписки. Хотя для самих подписок это требуется редко (так как подписки обычно срабатывают на той же стороне, где создается объект), в сложных цепочках вызовов БСП отсутствие этого флага может привести к невозможности корректной компиляции программного интерфейса модуля.
Чтобы устранить ошибку, выполним следующие действия:
ВыполнитьДействияПередЗаписьюПрисоединенногоФайла). Найдите её в дереве метаданных в разделе Общие -> Подписки на события.Обработчик. Там указано имя модуля и имя процедуры.Толстый клиент (управляемое приложение). Если же вы планируете использовать этот код в фоновых заданиях или внешних соединениях, убедитесь, что соответствующие флаги также установлены.Если изменять свойства типовых модулей (снимать конфигурацию с поддержки) нежелательно, рассмотрим другие варианты:
Самый правильный способ для современных конфигураций — тестировать и эксплуатировать код в режиме Тонкого клиента. В этом режиме работа с объектами происходит строго на сервере, где все серверные модули БСП гарантированно доступны, и проблемы с компиляцией клиентского контекста толстого клиента просто не возникнут.
Если вам критически важно выполнить операцию именно из сеанса, где возникают проблемы с контекстом, можно вынести удаление или изменение объектов в фоновое задание. Выясним, почему это помогает: фоновое задание всегда запускается на сервере в чистом серверном контексте. Рассмотрим пример запуска:
// Код в модуле обработки или формы
ПараметрыЗадания = Новый Структура("СсылкаНаФайл", НужнаяСсылка);
ФоновыеЗадания.Выполнить("МойОбщийМодуль.УдалитьФайлНаСервере", ПараметрыЗадания);
// Код в серверном общем модуле
Процедура УдалитьФайлНаСервере(Параметры) Экспорт
ОбъектФайла = Параметры.СсылкаНаФайл.ПолучитьОбъект();
Если ОбъектФайла <> Неопределено Тогда
ОбъектФайла.Удалить();
КонецЕсли;
КонецПроцедуры
Также важно убедиться, что метод НайтиПоНаименованию() действительно нашел объект. Проанализируем ситуацию: если поиск вернул пустую ссылку, то ПолучитьОбъект() вернет Неопределено. Хотя в данном случае ошибка была именно в подписке, всегда полезно добавлять проверку типа:
ЭтоСсылка = Справочники.НоменклатураПрисоединенныеФайлы.НайтиПоНаименованию("2");
Если Не ЭтоСсылка.Пустая() Тогда
ЭтоОбъект = ЭтоСсылка.ПолучитьОбъект();
// Проверка, что объект успешно получен и инициализирован
Если ЭтоОбъект <> Неопределено Тогда
ЭтоОбъект.Удалить();
КонецЕсли;
КонецЕсли;
Важное примечание: В некоторых релизах БСП (Библиотеки стандартных подсистем) наблюдались ошибки в самих обработчиках, когда процедура была описана с недостаточным количеством параметров для события ПриКопировании. В этом случае поможет только обновление конфигурации или исправление сигнатуры процедуры в общем модуле, если это допустимо правилами поддержки вашей системы.
Подводя итог, можно сказать, что ошибка «Обработчик события не найден» при использовании ПолучитьОбъект() — это почти всегда сигнал о том, что конфигурация «не видит» код из-за ограничений контекста. Проверьте режим запуска и флаги компиляции общих модулей, и проблема будет решена.