Почему в поле ввода 1С внезапно появляется надпись "Объект не найден"?

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

Разберем одну из самых неприятных ситуаций, с которой сталкиваются разработчики при проектировании форм документов: почему в поле ввода, привязанном к реквизиту, внезапно появляется пугающая надпись «Объект не найден», даже если документ еще даже не был записан в базу?

Причина возникновения проблемы

Основная причина кроется в особенностях жизненного цикла объекта в памяти платформы 1С. Когда вы программно работаете с документом, который только что создали, но еще не сохранили, платформа присваивает ему уникальный идентификатор (GUID). Если в коде (например, в обработчике ПередЗаписью) вы получаете ссылку через метод ПолучитьСсылку() и записываете ее в какой-либо реквизит, вы сохраняете этот GUID в памяти.

Если после этого в транзакции записи происходит ошибка, срабатывает Отказ = Истина или транзакция прерывается по другой причине, объект физически не попадает в базу данных. Однако переменная, содержащая ссылку, продолжает хранить GUID. Когда форма пытается отрисовать значение этого реквизита, 1С обращается к базе данных, не находит там записи с таким идентификатором и выдает пользователю «Объект не найден».

Разбор архитектурной ошибки

Часто разработчики сталкиваются с необходимостью «закольцевать» документ на самого себя для отслеживания цепочки событий. Это порождает классическую проблему: запись ссылки на объект до того, как этот объект стал «постоянным» в базе данных. Рассмотрим типичный ошибочный сценарий:


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

В этом примере, если запись прерывается, в памяти объекта остается ссылка на несуществующий в базе документ. Поле ввода, связанное с ПервичныйДокумент, будет отображать ошибку.

Как исправить ситуацию: пошаговые рекомендации

Чтобы избежать подобных инцидентов, рассмотрим несколько стратегий решения:

  1. Перенос записи в событие ПослеЗаписи. Не стоит пытаться заполнить реквизит ссылкой на самого себя до завершения транзакции записи. Используйте событие ПослеЗаписи, где объект уже гарантированно записан в базу.
  2. Использование проверки ЭтоНовый(). Перед выполнением кода, который заполняет реквизиты ссылками, всегда проверяйте состояние объекта. Если объект новый, отложите присвоение ссылки.
  3. Очистка реквизита при отмене записи. Если архитектурно необходимо заполнять поле до записи, предусмотрите обработчик, который принудительно очистит этот реквизит, если транзакция была отменена.

Пример безопасного подхода

Попробуем перестроить нашу логику так, чтобы она стала устойчивой к ошибкам записи. Вместо попыток записать ссылку «на лету», используем событие ПослеЗаписи для объектов, которые уже зафиксированы в базе данных:


Процедура ПослеЗаписи(Отказ, РежимЗаписи, РежимПроведения)
    Если Не Отказ И ЭтоНовый() Тогда
        // Записываем ссылку только после успешной фиксации в базе
        ЭтотОбъект.ПервичныйДокумент = ЭтотОбъект.Ссылка;
        // Повторно записываем, чтобы сохранить значение реквизита
        Записать(); 
    КонецЕсли;
КонецПроцедуры

Профилактика и диагностика

Чтобы в будущем оперативно отлавливать такие ситуации, рекомендуем следующие действия:

Анализ кода. Просмотрите все обработчики, где происходит изменение реквизитов, имеющих составной тип или определяемый тип. Ищите места, где метод ПолучитьСсылку() используется в связке с реквизитами, отображаемыми в интерфейсе.

Использование Технологического журнала. Если ошибка воспроизводится редко, настройте ТЖ на событие DBPROC. Это позволит увидеть, в какой момент происходит обращение к неверному GUID, и понять, какая именно часть алгоритма приводит к записи некорректной ссылки.

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

Помните, что запись «ссылки нового» — это работа с фантомом. Главная цель разработчика — сделать так, чтобы в базе данных всегда хранились только актуальные и существующие ссылки. Соблюдая правила транзакционности, вы избавите пользователей от проблем с «битыми» данными.

← На главную