При разработке механизмов обмена данными, особенно при выгрузке документов в формат XML, программисты часто сталкиваются с ошибкой «Поле объекта не обнаружена». Рассмотрим типичную ситуацию на примере выгрузки документа ПриобретениеУслугПрочихАктивов. Эта ошибка возникает в тот момент, когда код пытается обратиться к данным, которые не были получены из базы данных в ходе выполнения запроса.
Разберем исходный код, представленный в вопросе. Проблема кроется в обращении к результату запроса внутри цикла Пока РезультатЗап.СледующийЦикл(). Программа пытается выполнить следующую строку:
ЗаписьXML.ЗаписатьАтрибут("ОрганизацииИНН",Строка(РезультатЗап.ОрганизацияИНН));
Выясним, почему 1С выдает ошибку. Переменная РезультатЗап является объектом типа ВыборкаИзРезультатаЗапроса. В отличие от ссылки на объект (например, ссылки на справочник или документ), выборка содержит только те поля, которые были явно перечислены в секции ВЫБРАТЬ текста запроса.
Если мы посмотрим на текст запроса в первом сообщении, то увидим поля Организация и Контрагент, но полей ОрганизацияИНН или КонтрагентИНН там нет. Платформа 1С не может «догадаться», что под ОрганизацияИНН вы подразумеваете ИНН из справочника организаций, если это не прописано в метаданных самого запроса.
Проанализируем самый правильный с точки зрения производительности метод решения проблемы. Нам необходимо изменить текст запроса так, чтобы система сразу извлекла ИНН из связанных справочников. Для этого мы используем обращение через точку прямо в тексте запроса. Это заставит СУБД выполнить соединение таблиц на уровне сервера.
Изменим фрагмент запроса следующим образом:
Запрос1.Текст="ВЫБРАТЬ
| ПриобретениеУслугПрочихАктивов.Ссылка КАК Ссылка,
| ПриобретениеУслугПрочихАктивов.Организация КАК Организация,
| ПриобретениеУслугПрочихАктивов.Организация.ИНН КАК ОрганизацияИНН,
| ПриобретениеУслугПрочихАктивов.Контрагент КАК Контрагент,
| ПриобретениеУслугПрочихАктивов.Контрагент.ИНН КАК КонтрагентИНН,
...
После такого изменения поле ОрганизацияИНН станет доступно в выборке, и ошибка исчезнет. Рассмотрим преимущества этого метода: данные подтягиваются одним пакетом, что минимизирует количество обращений к базе данных.
Посмотрим на другой вариант, который предложили участники форума в сообщении №7. Если по какой-то причине вы не хотите менять текст запроса, вы можете обратиться к ИНН через уже полученную ссылку на организацию:
ЗаписьXML.ЗаписатьАтрибут("ОрганизацииИНН", Строка(РезультатЗап.Организация.ИНН));
ЗаписьXML.ЗаписатьАтрибут("КонтрагентИНН", Строка(РезультатЗап.Контрагент.ИНН));
Важное предупреждение: как верно подмечено в сообщении №8, такой подход считается «плохим тоном» в разработке на платформе 1С. Когда вы пишете РезультатЗап.Организация.ИНН внутри цикла, система для каждой строки результата выполняет отдельный неявный запрос к базе данных, чтобы получить значение ИНН. Если в вашей выборке будет 1000 документов, программа сделает 1000 лишних запросов, что значительно замедлит работу обработки.
Проанализируем ситуацию дальше. Как только вы исправите ошибку с ОрганизацияИНН, вы неизбежно столкнетесь с аналогичной проблемой для поля КонтрагентИНН. В современных конфигурациях (таких как ERP 2.5 или Управление торговлей 11) важно помнить о различии между Партнерами и Контрагентами.
Убедитесь, что в вашем документе заполнено именно поле Контрагент, прежде чем пытаться получить его ИНН, иначе вы рискуете получить пустое значение или ошибку при обращении к пустому объекту.
Разберем еще несколько моментов, которые помогут сделать вашу выгрузку более стабильной:
1. Использование функции XMLСтрока
Вместо стандартной функции Строка() для преобразования даты или чисел, при записи в XML рекомендуется использовать XMLСтрока(). Это гарантирует, что формат данных (особенно дат) будет соответствовать международному стандарту XML и успешно прочитается принимающей стороной.
2. Проверка на NULL
При использовании левых соединений (или обращений через точку в запросе) значение реквизита может оказаться NULL, если объект не заполнен. В запросе полезно использовать функцию ЕСТЬNULL():
| ЕСТЬNULL(ПриобретениеУслугПрочихАктивов.Организация.ИНН, "") КАК ОрганизацияИНН
3. Режим записи документа
В коде автора присутствует строка Док.Записать(РежимЗаписиДокумента.Проведение);. Проанализируем это действие: перепроводить документ только ради того, чтобы изменить статус выгрузки — это избыточная и опасная операция. Проведение может изменить бухгалтерские итоги или заблокировать работу других пользователей. Рассмотрим альтернативу: если вам нужно просто сохранить признак «Выгружен», лучше использовать РежимЗаписиДокумента.Запись или записывать данные в отдельный РегистрСведений.
Мы выяснили, что ошибка «Поле объекта не обнаружена» в контексте запроса всегда означает отсутствие колонки в результирующей таблице. Для исправления достаточно добавить нужное поле в секцию ВЫБРАТЬ вашего запроса, используя путь через точку от основной ссылки. Это обеспечит и работоспособность кода, и высокую скорость выполнения вашей обработки.