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