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