Почему возникает ошибка «Элемент не выбран!» при вызове ПолучитьОбъект() в Конвертации данных 2 и как её исправить?

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

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

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

Ошибка при вызове метода контекста (ПолучитьОбъект): Элемент не выбран!

Разберем подробно причину появления этой ошибки и рассмотрим эффективные варианты её устранения.

Выясняем причину ошибки: особенности жизненного цикла объекта при загрузке

Проанализируем механику работы подсистемы обмена. Ошибка «Элемент не выбран!» возникает тогда, когда метод ПолучитьОбъект() вызывается у пустой ссылки (ДокументСсылка.ПустаяСсылка()), значения Неопределено или у ссылки на объект, который физически еще не записан в информационную базу данных приемника.

Важно понимать разницу между этапами обработки объекта в Конвертации данных:

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

Решение 1. Явная запись объекта в обработчике «ПослеЗагрузкиОбъекта»

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

В обработчике правил конвертации объектов ПослеЗагрузкиОбъекта укажем следующий код:


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

Разберем важную деталь: после вызова метода Объект.Записать() необходимо установить переменную ОбъектМодифицирован = Ложь;. Это сообщает подсистеме обмена, что объект уже сохранен в БД и штатную дублирующую запись выполнять не требуется.

После этого в обработчике ПослеЗагрузкиДанных обход таблицы с проведением будет выполняться без ошибок:


Если Параметры.ТаблицаДокументов.Количество() > 0 Тогда 
    Параметры.ТаблицаДокументов.Сортировать("ДатаДок Возр");
    
    Для Каждого СтрокаТч Из Параметры.ТаблицаДокументов Цикл
        // Проверяем корректность ссылки перед получением объекта
        Если ЗначениеЗаполнено(СтрокаТч.СсылкаДок) И НЕ СтрокаТч.СсылкаДок.Пустая() Тогда
            ОбъектДок = СтрокаТч.СсылкаДок.ПолучитьОбъект();
            
            Попытка
                // Отключаем режим загрузки для выполнения бизнес-логики проведения
                ОбъектДок.ОбменДанными.Загрузка = Ложь;
                ОбъектДок.Записать(РежимЗаписиДокумента.Проведение);
                Сообщить("Документ проведен: " + СокрЛП(ОбъектДок));
            Исключение
                Сообщить("Ошибка проведения документа: " + ОписаниеОшибки());
            КонецПопытки;
        КонецЕсли;
    КонецЦикла;    
КонецЕсли;

Решение 2. Использование штатного параметра «РежимЗаписи» без ручного сбора ссылок

В Конвертации данных 2 предусмотрен штатный механизм проведения документов, который избавляет от необходимости вручную формировать таблицу значений и вызывать метод ПолучитьОбъект().

В обработчике ПередЗагрузкойОбъекта или ПослеЗагрузкиОбъекта можно переопределить встроенные параметры записи:


Если ИмяТипаОбъекта = "Документ" Тогда
    // Задаем штатное проведение при загрузке
    РежимЗаписи = "Проведение";
    РежимПроведения = "Неоперативный";
КонецЕсли;

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

Рекомендации по надежной работе с ссылочными типами в КД 2

  1. Проверка заполненности ссылок: Всегда проверяйте ссылки перед вызовом метода ПолучитьОбъект() с помощью функций ЗначениеЗаполнено() и метода Пустая().
  2. Управление режимом обмена данными: По умолчанию при загрузке объекту присваивается флаг Объект.ОбменДанными.Загрузка = Истина. Если вам требуется, чтобы при проведении формировались движения и срабатывали подписки на события конфигурации-приемника, явно сбрасывайте этот флаг в Ложь перед вызовом Записать(РежимЗаписиДокумента.Проведение).
  3. Безопасная обработка в цикле: Всегда оборачивайте операции проведения в блок Попытка ... Исключение, чтобы отказ в проведении одного документа не прерывал выполнение всего алгоритма загрузки.
← На главную