Как загрузить результат запроса с вложенной табличной частью в ДанныеФормыКоллекция

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

При разработке управляемых форм часто возникает задача отображения связанных данных по схеме «Мастер–Деталь» (например, в верхней таблице отображается список документов, а в нижней — табличная часть текущего выбранного документа). Если разработчик пытается получить единым запросом шапку и вложенную выборку строк, а затем применить метод Загрузить() к реквизиту формы типа ДанныеФормыКоллекция, возникает проблема: скалярные колонки (дата, номер, контрагент) успешно заполняются, а колонка с вложенной таблицей остается пустой.

Разберем причины такого поведения платформы «1С:Предприятие 8.3», выясним ограничения стандартных методов и рассмотрим рабочие способы решения данной задачи.

Почему метод Загрузить() не заполняет вложенные таблицы

Проанализируем механику работы платформы с коллекциями управляемой формы:

  1. Поверхностное копирование: Стандартный метод ДанныеФормыКоллекция.Загрузить() выполняет прямое сопоставление по именам колонок и переносит только значения простых типов (строки, числа, даты, булево, ссылки). Рекурсивная загрузка вложенных таблиц и коллекций этим методом не предусмотрена.
  2. Особенности типизации данных формы: Тип ТаблицаЗначений существует только на сервере и не может являться полноценным типом данных ячейки в объекте ДанныеФормыКоллекция. Вложенные списки на форме должны быть объявлены как подчиненные реквизиты формы (подчиненные коллекции) либо обрабатываться отдельно.
  3. Раздувание контекста формы: Если помещать в каждую строку таблицы формы вложенные структуры данных, объем данных, передаваемых между клиентом и сервером при каждом контекстном вызове, резко возрастает, что приводит к зависаниям интерфейса.

Способ 1. Заполнение строк в цикле с методом Загрузить() для подчиненной коллекции

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

Посмотрим на пример серверного кода:


РезультатЗапроса = Запрос.Выполнить().Выгрузить();

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

Этот способ решает задачу в лоб, однако при большом объеме строк в документе и длинном списке документов он может вызывать просадку производительности и увеличивать объем формы в памяти.

Способ 2. Использование двух плоских таблиц с отбором на форме (Рекомендуемый)

Вместо формирования вложенных таблиц в запросе мы можем разделить данные на две независимые плоские таблицы и связать их на форме по идентификатору или ссылке.

  1. В запросе получаем два пакета: список документов (шапка) и плоский список всех строк табличных частей с ключевым полем связи (например, Ссылка или УникальныйИдентификатор).
  2. Загружаем результаты в два независимых реквизита формы: ТаблицаДокументов и ТаблицаВсехСтрок с помощью быстрого метода .Загрузить().
  3. При активизации строки в верхней таблице устанавливаем отбор для отображаемой нижней таблицы или копируем отфильтрованные строки.

Рассмотрим реализацию заполнения на сервере:


// Выполняем пакетный запрос
ПакетРезультатов = Запрос.ВыполнитьПакет();

// Загружаем шапки документов
ТаблицаДокументов.Загрузить(ПакетРезультатов[0].Выгрузить());

// Загружаем все детальные строки
ТаблицаВсехСтрок.Загрузить(ПакетРезультатов[1].Выгрузить());

В обработчике события ПриАктивизацииСтроки верхней таблицы на клиенте мы просто фильтруем или перезаполняем подчиненную таблицу строк текущего документа без лишних серверных вызовов.

Способ 3. Ленивая загрузка строк по требованию (On-Demand)

Если документов много, а их табличные части объемные, оптимально не передавать все строки на форму сразу, а запрашивать их только при смене текущей строки в мастер-таблице.

  1. В форму загружается только список документов (шапка).
  2. Назначается обработчик события ПриАктивизацииСтроки для таблицы ТаблицаДокументов.
  3. При выборе строки отправляется серверный вызов, который считывает табличную часть только для одного активного документа и быстро загружает ее в нижнюю таблицу формы.
  4. Для оптимизации интерфейса и исключения лишних серверных вызовов при быстрой навигации стрелками клавиатуры рекомендуется использовать вызов через ПодключитьОбработчикОжидания с минимальной задержкой (0.1–0.2 секунды).

&НаКлиенте
Процедура ТаблицаДокументовПриАктивизацииСтроки(Элемент)
    ПодключитьОбработчикОжидания("ОбновитьПодчиненнуюТаблицу", 0.2, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьПодчиненнуюТаблицу()
    ТекДанные = Элементы.ТаблицаДокументов.ТекущиеДанные;
    Если ТекДанные <> Неопределено Тогда
        ЗаполнитьСтрокиДокументаНаСервере(ТекДанные.Ссылка);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьСтрокиДокументаНаСервере(СсылкаНаДокумент)
    ТаблицаТоваров.Загрузить(СсылкаНаДокумент.Товары.Выгрузить());
КонецПроцедуры

Способ 4. Использование связанных Динамических списков

Если форма предназначена исключительно для просмотра данных и анализа (без непосредственного редактирования строк «на лету»), наиболее производительным решением будет использование двух элементов типа ДинамическийСписок:

  1. Создаем основной динамический список для документов.
  2. Создаем подчиненный динамический список для строк табличной части с параметром в запросе (например, ГДЕ Документ = &ТекущийДокумент).
  3. В свойстве динамического списка Связь по владельцу или в событии ПриАктивизацииСтроки передаем ссылку текущей строки в параметр подчиненного списка.

Этот подход гарантирует минимальный расход оперативной памяти и максимальную скорость открытия и работы формы за счет считывания данных порциями непосредственно средствами СУБД.

← На главную