Как вывести значения из табличной части документа в форму списка 1С

Программист 1С v8.3 (Обычные формы)
← На главную

В практике разработки на платформе 1С часто возникает задача отобразить информацию из табличной части документа непосредственно в списке документов. Например, пользователю важно видеть список заказов покупателей или номенклатуру прямо в общем журнале, не открывая каждый документ. Реализация этой задачи требует понимания архитектуры форм и механизмов работы с данными, чтобы не допустить критического замедления работы системы. Разберем подробно, как это сделать правильно для разных типов форм.

Проблема производительности при выводе данных

Прежде чем переходить к коду, проанализируем типичную ошибку начинающих разработчиков. Попытка получить данные запросом в цикле или через функции, вызываемые для каждой строки (например, в событии ПриВыводеСтроки), приводит к так называемой проблеме «N+1 запроса». Если в списке отображается 30 строк, система сделает 30 отдельных запросов к базе данных, что мгновенно «подвесит» интерфейс при прокрутке. Поэтому нашей основной целью будет минимизация обращений к серверу.

Решение для обычных форм: Использование события ПриПолученииДанных

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

  1. Добавим в форму списка колонку (без привязки к данным), назовем ее ЗаказыПокупателя.
  2. В модуле формы создадим обработчик ПриПолученииДанных.
  3. Внутри обработчика соберем все ссылки на документы, которые в данный момент видны пользователю, выполним один запрос к табличной части и распределим результат по строкам.

Разберем пример кода для реализации этой логики:


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

Важный нюанс: Если в табличной части документа несколько строк, запрос вернет несколько записей для одной ссылки. В этом случае нам нужно будет предварительно свернуть результат запроса или использовать Соответствие, где значением будет накопленная строка с перечислением сделок через запятую.

Решение для управляемых форм: Динамический список и денормализация

В управляемых формах (УФ) подход принципиально иной. Динамический список работает на базе системы компоновки данных (СКД). Прямое соединение основной таблицы с табличной частью в запросе динамического списка приведет к дублированию строк в списке документов (один документ повторится столько раз, сколько строк в его табличной части). Чтобы этого избежать, используем один из следующих методов:

Метод денормализации данных (самый производительный)

Проанализируем ситуацию: чтение табличной части «на лету» всегда нагружает систему. Лучшее решение — подготовить данные заранее. Для этого выполним следующие действия:

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

Рассмотрим пример формирования такой строки в модуле объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    СписокСделок = "";
    Для Каждого СтрокаТЧ Из РасшифровкаПлатежа Цикл
        ПредставлениеСделки = Строка(СтрокаТЧ.Сделка);
        Если Найти(СписокСделок, ПредставлениеСделки) = 0 Тогда
            СписокСделок = СписокСделок + ?(СписокСделок = "", "", ", ") + ПредставлениеСделки;
        КонецЕсли;
    КонецЦикла;
    
    СоставСделокСтрокой = СписокСделок;
КонецПроцедуры

Этот метод считается «золотым стандартом» для высоконагруженных систем, так как при открытии списка 1С просто считывает уже готовую строку из таблицы документа, не выполняя сложных соединений с табличными частями.

Альтернативное решение: Вспомогательная таблица (Панель предварительного просмотра)

Иногда выводить данные через запятую в узкую колонку неудобно — информация получается нечитаемой. В таком случае рассмотрим интерфейсное решение, часто применяемое в типовых конфигурациях. Мы не будем пытаться впихнуть невпихуемое в одну строку списка, а добавим под основным списком документов небольшую табличную часть формы.

Выясним, как это работает по шагам:

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

Пример кода для Управляемых Форм (событие ПриАктивизацииСтроки):


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

&НаСервере
Процедура ОбновитьПодчиненнуюТаблицу(СсылкаНаДокумент)
    // Здесь заполняем реквизит формы (таблицу), который отображает состав документа
    // Например, через запрос к табличной части СсылкаНаДокумент.РасшифровкаПлатежа
КонецПроцедуры

Заключение

Подведем итог: если вы работаете в обычных формах, ваш выбор — событие ПриПолученииДанных с пакетным запросом. Если вы используете управляемые формы, наиболее эффективным и быстрым способом будет денормализация (хранение данных ТЧ в строковом реквизите документа). Использование запросов в динамических списках для агрегации строк через запятую в 1С затруднено отсутствием встроенных функций типа STRING_AGG, поэтому программная подготовка данных при записи документа остается лучшим архитектурным решением.

← На главную