При работе с инструментом «1С:Конвертация данных 2.1» программисты часто сталкиваются с ситуацией, когда отлаженные правила внезапно перестают работать после обновления одной из конфигураций. Рассмотрим типовой случай: при выгрузке документа ОтчетПроизводстваЗаСмену из УПП 1.3 в Бухгалтерию предприятия 2.0 возникает ошибка: «Ошибка получения значения свойства подчиненного объекта (по имени свойства приемника)». При этом система сообщает, что поле объекта СуммаПлановая не обнаружено.
Проанализируем ситуацию, выясним причину такого поведения платформы и разберем способы решения — от быстрого исправления «в лоб» до архитектурно правильной оптимизации обмена.
Разберем внутренние механизмы работы обработки УниверсальныйОбменДаннымиXML. В правилах конвертации свойств (ПКС) у нас есть два варианта получения данных:
Перед выгрузкой.Если в ПКС не указан источник, система ожидает, что в программном коде обработчика Перед выгрузкой будет явно заполнена специальная переменная Значение. Однако здесь кроется важный нюанс: если выполнение кода в обработчике не приводит к присваиванию какого-либо значения этой переменной (например, выполнение программы пошло по ветке условия Если...Иначе, где нет присваивания), алгоритм обмена переходит к поиску по имени.
Система рассуждает так: «Программист не указал источник и не передал ничего в переменную Значение. Попробую-ка я найти в объекте-источнике реквизит, имя которого совпадает с именем свойства в приемнике». В нашем случае в документе-источнике (УПП) реквизита СуммаПлановая нет (он может называться иначе или отсутствовать в табличной части), и 1С выдает закономерную ошибку: Поле объекта не обнаружено (СуммаПлановая).
Посмотрим на пример кода, который часто становится причиной такой ошибки. Проблема заключается в том, что установка переменной Значение обернута в условия, которые могут не выполниться для конкретной строки документа.
// Пример проблемного кода в ПКС "Перед выгрузкой"
Запросы.Запрос1.УстановитьПараметр("Регистратор", Источник.Ссылка);
Запросы.Запрос1.УстановитьПараметр("Ном", ОбъектКоллекции.Номенклатура);
Рез = Запросы.Запрос1.Выполнить().Выгрузить();
Если Рез.Количество() > 0 Тогда
Если Рез[0].Стоимость > 0 Тогда
Значение = Число(Рез[0].Стоимость / ОбъектКоллекции.Количество);
КонецЕсли;
КонецЕсли;
// Если Рез.Количество() равно 0, переменная "Значение" останется не инициализированной!
Проанализируем ситуацию: если запрос вернул пустой результат, код внутри условия Если не исполнится. Переменная Значение не будет определена, и обработка выгрузки попытается обратиться к свойству Источник.СуммаПлановая, что и приведет к аварийному завершению обмена.
Самый простой и эффективный способ исправить ситуацию — гарантировать, что переменная Значение будет определена в любом случае, даже если запросы не вернули данных. Для этого в самой первой строке обработчика Перед выгрузкой необходимо добавить инициализацию.
Рассмотрим исправленный вариант кода:
// 1. Обязательная инициализация!
Значение = 0;
// Далее идет основной алгоритм
Запросы.Запрос33.УстановитьПараметр("Ссылка", Источник.Ссылка);
Запросы.Запрос33.УстановитьПараметр("Ном", ОбъектКоллекции.Номенклатура);
Рез33 = Запросы.Запрос33.Выполнить().Выгрузить();
Если Рез33.Количество() > 0 Тогда
Если Рез33[0]._ИнкомСтоимостьИзготовления <> 0 Тогда
Значение = Число(Рез33[0]._ИнкомСтоимостьИзготовления);
КонецЕсли;
КонецЕсли;
// Проверяем дополнительные условия, если значение все еще 0
Если Значение = 0 Тогда
// Дополнительная логика поиска цены...
Значение = 1000; // Технический дефолт, если ничего не найдено
КонецЕсли;
Теперь, даже если ни одно условие не сработает, переменная Значение будет содержать число 0. Система увидит, что значение определено, и не будет пытаться искать реквизит в объекте-источнике по имени.
Важно понимать, что использование запросов в обработчиках ПКС (особенно для свойств табличных частей) — это огромная нагрузка на систему. Если в документе 100 строк продукции, и для каждой строки выполняется 3 запроса, то для одного документа мы получим 300 обращений к базе данных. Это классическая проблема «N+1 запрос».
Выясним, как сделать обмен быстрее. Правильнее будет подготовить все данные заранее в обработчике ПКО (Правило конвертации объекта) Перед выгрузкой самого документа и передать их в ПКС через структуру ВходящиеДанные.
Рассмотрим алгоритм оптимизации по шагам:
Таблицу Значений или Соответствие и помещаем в переменную ВходящиеДанные.ВходящиеДанные по ключу (например, по ссылке на номенклатуру).Пример кода в ПКО Перед выгрузкой:
// Собираем данные один раз на весь документ
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Номенклатура, Сумма ИЗ Регистр... ГДЕ Регистратор = &Регистратор";
Запрос.УстановитьПараметр("Регистратор", Источник.Ссылка);
// Помещаем результат в структуру ВходящиеДанные для передачи в ПКС
ТаблицаЦен = Запрос.Выполнить().Выгрузить();
ТаблицаЦен.Индексы.Добавить("Номенклатура");
ВходящиеДанные = Новый Структура;
ВходящиеДанные.Вставить("ТаблицаПлановыхЦен", ТаблицаЦен);
Пример кода в ПКС Перед выгрузкой:
Значение = 0;
Если ВходящиеДанные <> Неопределено Тогда
СтрокаЦены = ВходящиеДанные.ТаблицаПлановыхЦен.Найти(ОбъектКоллекции.Номенклатура, "Номенклатура");
Если СтрокаЦены <> Неопределено Тогда
Значение = СтрокаЦены.Сумма;
КонецЕсли;
КонецЕсли;
Такой подход сокращает количество запросов с сотен до одного, что кардинально ускоряет выгрузку данных.
Как мы увидели в обсуждении, иногда невозможно включить режим отладки на сервере из-за ограничений инфраструктуры. В таких случаях проанализируем ситуацию с помощью «логирования на коленке».
Используйте метод Сообщить() или намеренную генерацию ошибки. Если вы хотите узнать, чему равна переменная в конкретный момент, можно использовать конструкцию:
// Временная вставка для отладки
Если Источник.Номер = "ЗД000000187" Тогда
ВызватьИсключение "Значение переменной Рез.Количество(): " + Строка(Рез.Количество());
КонецЕсли;
Это позволит вам увидеть значение переменной прямо в окне сообщений об ошибке при запуске обмена, не используя конфигуратор. Важно: не забудьте удалить этот код перед сохранением финальной версии правил.
Подведем итоги. Ошибка «Поле объекта не обнаружено» в Конвертации данных чаще всего является следствием того, что алгоритм «провалился» мимо установки значения и включил механизм поиска по имени. Чтобы этого избежать, всегда инициализируйте переменную Значение в самом начале кода ПКС. А для повышения стабильности и скорости работы — старайтесь выносить тяжелые запросы из свойств табличных частей на уровень всего объекта.