При разработке печатных форм в 1С, особенно в конфигурациях вроде 1С:Управление нашей фирмой (УНФ), программисты часто сталкиваются с ошибками при попытке вывести данные из вложенных таблиц, таких как состав спецификации. Ошибка Поле объекта не обнаружено (Состав) может сигнализировать о целом ряде проблем: от простой опечатки до глубоких логических ошибок в структуре запроса. Рассмотрим подробнее, как проанализировать код и найти причину неисправности.
Проанализируем фрагмент кода, представленный в вопросе. Это самая распространенная «пятничная» ошибка. Обратите внимание на инициализацию и выполнение запроса:
ЗапросСпецификация = Новый Запрос;
// ... установка параметров и текста для ЗапросСпецификация ...
Спецификация = Запрос.Выполнить().Выбрать();
Выясним причину: автор создает объект запроса с именем ЗапросСпецификация, настраивает его текст и параметры, но в следующей строке пытается выполнить совершенно другой объект — Запрос. Если переменная Запрос была определена где-то выше в коде (например, для получения данных шапки документа), то в ее результате, скорее всего, нет поля Состав. Именно поэтому система выдает ошибку Поле объекта не обнаружено при попытке обращения к выборке.
Решение: Всегда проверяйте соответствие имен переменных. В данном случае необходимо изменить строку выполнения на:
Спецификация = ЗапросСпецификация.Выполнить().Выбрать();
В тексте запроса используется конструкция выбора вложенной таблицы: Спецификации.Состав.(...) КАК Состав. В системе 1С работа с такими данными имеет свои особенности. Разберем по шагам, что происходит при выполнении Запрос.Выполнить().Выбрать().
Поле Состав в данном случае не является ТаблицейЗначений, которую можно выгрузить методом .Выгрузить(). Это объект типа ВыборкаИзРезультатаЗапроса. Попытка вызвать метод выгрузки непосредственно у поля выборки приведет к ошибке, так как этот метод доступен только для всего объекта РезультатЗапроса или для табличных частей объектов метаданных.
Рассмотрим, как правильно организовать обход вложенной таблицы спецификации:
ВыборкаЗапрос = ЗапросСпецификация.Выполнить().Выбрать();
Пока ВыборкаЗапрос.Следующий() Цикл
// Получаем выборку по вложенной таблице "Состав"
ВыборкаСостав = ВыборкаЗапрос.Состав.Выбрать();
Пока ВыборкаСостав.Следующий() Цикл
// Здесь мы работаем с конкретной строкой состава
ДанныеПечати.Вставить("Номенклатура", ВыборкаСостав.Номенклатура);
// ... заполнение остальных параметров ...
КонецЦикла;
КонецЦикла;
Использование Спецификация.Состав.Выгрузить() — это грубая ошибка типизации в контексте работы с выборками из результата запроса.
Проанализируем секции ИЗ и ГДЕ в представленном коде. Программист указывает две таблицы через запятую:
ИЗ
Документ.ЗаказНаПроизводство КАК ЗаказНаПроизводство,
Справочник.Спецификации КАК Спецификации
ГДЕ
ЗаказНаПроизводство.Ссылка В(&МассивОбъектов)
И Спецификации.Ссылка В(&МассивОбъектов)
Это классический пример отсутствия связи между таблицами. В реляционных базах данных это порождает так называемое Декартово произведение: каждая строка из таблицы заказов будет соединена с каждой строкой из таблицы спецификаций. Если в массиве 10 заказов и 10 спецификаций, вы получите 100 строк в результате, большинство из которых будут неверными.
Более того, условие Спецификации.Ссылка В(&МассивОбъектов) выглядит подозрительно. Обычно в массиве объектов для печати передаются ссылки на документы (Заказы). Ссылки на спецификации являются реквизитами этих документов. Посмотрим на пример того, как должен выглядеть правильный запрос с соединением:
ВЫБРАТЬ
ЗаказНаПроизводство.Ссылка КАК Ссылка,
СпецификацииСостав.Номенклатура КАК Номенклатура,
СпецификацииСостав.Количество КАК Количество
ИЗ
Документ.ЗаказНаПроизводство КАК ЗаказНаПроизводство
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Спецификации.Состав КАК СпецификацииСостав
ПО ЗаказНаПроизводство.Спецификация = СпецификацииСостав.Ссылка
ГДЕ
ЗаказНаПроизводство.Ссылка В(&МассивОбъектов)
Такой подход (через «плоский» запрос с соединением) зачастую эффективнее и проще в обработке, чем использование вложенных таблиц в запросе.
Даже если исправить опечатку в переменной Запрос, код упадет на строке СтрокаТабличнойЧастиСпецификации.НомерСтроки. Посмотрим на текст исходного запроса: там выбираются только Количество, КоличествоПродукции и Номенклатура. Поля НомерСтроки, ПредставлениеНоменклатуры и ЕдиницаИзмерения в запросе отсутствуют.
Для исправления ситуации выполним следующие действия:
Номенклатура.Наименование или функцию ПРЕДСТАВЛЕНИЕ(Номенклатура).Пример оптимизированного запроса внутри кода:
Запрос.Текст =
"ВЫБРАТЬ
| СпецификацииСостав.НомерСтроки КАК НомерСтроки,
| СпецификацииСостав.Номенклатура.Представление КАК ПредставлениеНоменклатуры,
| СпецификацииСостав.Количество КАК Количество,
| СпецификацииСостав.Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения
|ИЗ
| Справочник.Спецификации.Состав КАК СпецификацииСостав
|ГДЕ
| СпецификацииСостав.Ссылка = &СпецификацияСсылка";
Подводя итог, можно сказать, что ошибка Поле объекта не обнаружено (Состав) в данном случае была вызвана перепутанными именами переменных. Однако, даже после её исправления, код потребовал бы значительной переработки из-за неправильного использования метода .Выгрузить() и отсутствия связей в запросе.
Помните:
Конструктор запроса — он помогает избежать ошибок в связях таблиц и автоматически подтягивает нужные поля (например, НомерСтроки).JOIN), это делает результат более предсказуемым и легким для отладки.ПечатьДокументовУНФ, но передавайте в них только те данные, которые вы реально получили в запросе.