Как исправить ошибку «Получение элемента по индексу для значения не определено» в 1С:Конвертация данных 2.0?

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

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

«Получение элемента по индексу для значения не определено»

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

Выясняем причину возникновения ошибки

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

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

Рассмотрим подробнее, как правильно переписать алгоритм выгрузки движений регистра.

Вариант 1. Использование специализированной функции ВыгрузитьРегистр() (Рекомендуемый способ)

Для ручной выгрузки движений регистров в КД 2.0 существует стандартная и наиболее правильная функция — ВыгрузитьРегистр(). Она позволяет выгрузить движения пакетами, группируя их по регистраторам, как это и требуется для наборов записей.

Разберем по шагам, как должен выглядеть код в ПВД (способ выгрузки — «Произвольный алгоритм»):


// 1. Создаем запрос для получения данных из регистра накопления
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   ТоварыНаСкладах.Период,
|   ТоварыНаСкладах.Регистратор,
|   ТоварыНаСкладах.ВидДвижения,
|   ТоварыНаСкладах.Номенклатура,
|   ТоварыНаСкладах.Характеристика,
|   ТоварыНаСкладах.Назначение,
|   ТоварыНаСкладах.Склад,
|   ТоварыНаСкладах.Помещение,
|   ТоварыНаСкладах.Серия,
|   ТоварыНаСкладах.ВНаличии,
|   ТоварыНаСкладах.КОтгрузке,
|   ТоварыНаСкладах.КонтролироватьОстатки
|ИЗ
|   РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
|ГДЕ
|   ТоварыНаСкладах.Период МЕЖДУ &Дата1 И &Дата2";

Запрос.УстановитьПараметр("Дата1", Параметры.ДатаНачало);
Запрос.УстановитьПараметр("Дата2", Параметры.ДатаКонец);

// Выгружаем все записи в Таблицу Значений (избегаем использования имени ВыборкаДанных)
ТаблицаЗаписей = Запрос.Выполнить().Выгрузить();

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

// Получаем уникальный список регистраторов из выгруженной таблицы движений
ТаблицаРегистраторов = ТаблицаЗаписей.Скопировать();
ТаблицаРегистраторов.Свернуть("Регистратор");

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

Важное примечание: При использовании этого метода в ПКО «ТоварыНаСкладах» на вкладке «Параметры» у свойств не требуется устанавливать флаги «Получить из входящих данных». Система сопоставит колонки переданной таблицы СтрокиДляВыгрузки с реквизитами приемника автоматически по совпадению имен.

Вариант 2. Переопределение коллекции объектов в ПКГС (Правила Конвертации Группы Свойств)

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

Шаг 1. В обработчике ПВД (Произвольный алгоритм) соберите всю таблицу движений регистра и передайте ее в параметре ВходящиеДанные:


ТаблицаДвижений = Запрос.Выполнить().Выгрузить();

ВходящиеДанные = Новый Структура;
ВходящиеДанные.Вставить("ЗаписиРегистра", ТаблицаДвижений);

// Вызываем выгрузку по правилу один раз, передавая всю таблицу целиком
ВыгрузитьПоПравилу(, , ВходящиеДанные, , "ТоварыНаСкладах");

Шаг 2. Перейдите в ПКО «ТоварыНаСкладах». В дереве свойств найдите группу свойств (обычно это корневая папка, содержащая реквизиты движений регистра, она отвечает за коллекцию записей).

Шаг 3. Откройте свойства этой группы (ПКГС) и перейдите в обработчик события «Перед обработкой». Напишите следующий код:

КоллекцияОбъектов = ВходящиеДанные.ЗаписиРегистра;

Благодаря этой строке кода механизм Конвертации данных не будет пытаться обращаться к пустому объекту-источнику по индексу (что приводило к ошибке), а сразу возьмет переданную нами таблицу значений ЗаписиРегистра и обработает ее строки.

Полезные советы при работе с ПВД в КД 2.0

Мы подробно разобрали причины возникновения ошибки и изучили два надежных метода ее обхода. Выбор конкретного варианта зависит от ваших архитектурных предпочтений, но использование функции ВыгрузитьРегистр() является наиболее стандартным и поддерживаемым решением в среде разработчиков 1С.

← На главную