Почему возникает ошибка «Поле объекта не обнаружено (Наименование)» при чтении XML и как правильно искать данные в справочнике

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

В практике разработки на платформе 1С:Предприятие 8 часто встречается задача импорта данных из внешних систем через формат XML. Использование технологии XDTO (XML Data Transfer Objects) является современным и эффективным способом десериализации данных, однако начинающие разработчики часто допускают ошибки в обращении к объектам и логике поиска существующих записей. Проанализируем типичную ситуацию, когда код, успешно работавший ранее, внезапно начинает выдавать ошибку доступа к свойствам объекта.

Разбор основной ошибки: Объект чтения против Объекта данных

Рассмотрим ситуацию, описанную в исходном сообщении. Программист использует объект ЧтениеXML для открытия файла и ФабрикаXDTO для его чтения. Ошибка «Поле объекта не обнаружено (Наименование)» возникает в строке поиска по реквизиту. Выясним причину этого сбоя.

Объект ЧтениеXML в 1С — это своего рода «курсор» или поток, который позволяет последовательно перемещаться по узлам XML-документа. Он не содержит в себе данных из файла в виде привычных свойств. Когда мы выполняем команду Результат = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML), все данные из потока вычитываются и преобразуются в объект ОбъектXDTO. После этого объект ЧтениеXML становится практически бесполезным для получения конкретных значений тегов.

В коде автора ошибка заключается в обращении: ЧтениеXML.Наименование. Поскольку у объекта ЧтениеXML нет свойства Наименование, система выбрасывает исключение. Правильным подходом является обращение к текущему элементу коллекции, полученной из XDTO. Рассмотрим исправленный фрагмент кода:


// Неправильно:
НайденнаяКарта = Справочники.ДисконтКарты.НайтиПоРеквизиту("Наименование", ЧтениеXML.Наименование);

// Правильно:
НайденнаяКарта = Справочники.ДисконтКарты.НайтиПоРеквизиту("Наименование", Элемент.Наименование);

Корректная проверка на существование элемента в базе

Вторая критическая ошибка в представленном коде — это сравнение результата поиска с Неопределено. Разберем подробнее, как работают методы поиска в 1С (НайтиПоНаименованию, НайтиПоКоду, НайтиПоРеквизиту). Эти методы никогда не возвращают Неопределено. Если поиск не увенчался успехом, они возвращают Пустую ссылку соответствующего типа.

Проанализируем ситуацию: если мы сравниваем ссылку с Неопределено, условие НайденнаяКарта <> Неопределено всегда будет истинным (поскольку пустая ссылка — это объект типа СправочникСсылка, и он не равен значению Неопределено). В итоге код будет считать, что карта всегда найдена, и оператор Продолжить будет пропускать создание новых элементов, либо (при другой логике) пытаться перезаписать пустую ссылку.

Правильная проверка должна выглядеть следующим образом:


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

Оптимизация поиска: Наименование vs Реквизит

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

Также стоит обратить внимание на типизацию. При чтении через XDTO значения свойств могут иметь специфические типы. Для надежности при поиске и присваивании строковых данных полезно использовать явное приведение к строке: Строка(Элемент.Наименование).

Безопасная работа с XDTO: Проверка наличия свойств

Часто ошибка «Поле объекта не обнаружено» возникает не только из-за обращения к неверному объекту, но и из-за того, что в самом XML-файле отсутствует ожидаемый тег. Например, в одном из элементов справочника в файле не заполнено поле Телефон. Если в схеме XDTO это поле не помечено как необязательное, обращение к нему в цикле вызовет остановку программы.

Посмотрим, как можно обезопасить наш код:

  1. Использовать метод Элемент.Свойства().Получить("ИмяСвойства") для проверки существования свойства в объекте XDTO.
  2. Обернуть блок чтения в конструкцию Попытка ... Исключение.
  3. Для регламентных заданий обязательно записывать текст ошибки в ЖурналРегистрации, чтобы можно было понять причину сбоя без отладки.

Пример надежной реализации цикла обработки данных:


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

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

Производительность и транзакции при загрузке данных

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

Проанализируем, как ускорить этот процесс. Правильным решением будет использование явного управления транзакциями. Мы открываем транзакцию перед началом цикла и фиксируем её один раз после завершения всех операций. Это ускоряет загрузку в десятки раз.


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

Проблемы контекста выполнения регламентных заданий

Если код «утром работал, а днем перестал», и при этом изменения в конфигурацию не вносились, стоит обратить внимание на внешние факторы. Поскольку код выполняется в регламентном задании, он запускается на стороне сервера под учетной записью службы 1С (например, USR1CV8).

Выясним возможные причины внезапного отказа:

Подводя итог, отметим, что для стабильной работы подобных интеграций необходимо не только исправлять синтаксические ошибки обращения к свойствам (Элемент вместо ЧтениеXML), но и закладывать механизмы обработки исключений и логирования. Это позволит быстро локализовать проблему, даже если она возникнет внезапно в процессе эксплуатации системы.

← На главную