Как вывести несколько значений из табличной части в одно поле динамического списка?

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

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

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

Способ 1. Денормализация данных (Создание текстового реквизита)

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

Суть заключается в том, что мы добавляем в сам объект (документ или справочник) дополнительный реквизит КраткийСостав с типом Строка (неограниченной длины или фиксированной, например, 250 символов). Этот реквизит будет обновляться автоматически при записи объекта.

Разберем реализацию по шагам:

  1. Добавьте реквизит КраткийСостав в метаданные объекта.
  2. В модуле объекта или в подписке на событие ПередЗаписью пропишите алгоритм формирования строки.

Пример кода для модуля объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Ограничим количество выводимых товаров, например, первыми пятью
    МаксКоличество = 5;
    Счетчик = 0;
    НоваяСтрокаСостава = "";
    
    Для Каждого СтрокаТЧ Из Товары Цикл
        Счетчик = Счетчик + 1;
        Если Счетчик > МаксКоличество Тогда
            НоваяСтрокаСостава = НоваяСтрокаСостава + "...";
            Прервать;
        КонецЕсли;
        
        Разделитель = ?(ЗначениеЗаполнено(НоваяСтрокаСостава), ", ", "");
        НоваяСтрокаСостава = НоваяСтрокаСостава + Разделитель + Строка(СтрокаТЧ.Номенклатура);
    КонецЦикла;
    
    КраткийСостав = НоваяСтрокаСостава;
    
КонецПроцедуры

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

Недостатки: Требуется перепополнение данных для уже существующих документов и небольшое увеличение объема базы данных.

Способ 2. Использование события ПриПолученииДанныхНаСервере

Если вносить изменения в структуру метаданных нельзя, мы можем воспользоваться событием формы ПриПолученииДанныхНаСервере. Этот метод позволяет динамически "дорисовывать" нужные данные в строки, которые в данный момент отображаются на экране у пользователя.

Проанализируем ситуацию: просто выполнять запрос в цикле внутри этого события нельзя — это создаст колоссальную нагрузку на сервер (проблема N+1 запроса). Правильный подход — собрать все ссылки отображаемых строк и получить данные одним запросом.

Рассмотрим пример реализации в модуле формы:


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

Важный нюанс: Для работы этого кода в динамическом списке должно быть добавлено произвольное поле КраткийСостав (например, через текст запроса списка как "" КАК КраткийСостав).

Способ 3. Левые соединения в запросе (Метод фиксированного количества)

Если мы точно знаем, что нам нужно вывести, например, строго первые 3 или 5 товаров, мы можем реализовать это непосредственно в тексте запроса динамического списка. Выясним причину, почему это редко используется: запрос становится громоздким и может замедлять работу базы при больших объемах ТЧ.

Проанализируем пример запроса для вывода первых двух товаров:


ВЫБРАТЬ
    Док.Ссылка КАК Ссылка,
    Док.Дата КАК Дата,
    Док.Номер КАК Номер,
    ЕСТЬNULL(ТЧ1.Номенклатура.Наименование, "") 
        + ВЫБОР КОГДА ТЧ2.Номенклатура ЕСТЬ НЕ NULL ТОГДА ", " + ТЧ2.Номенклатура.Наименование ИНАЧЕ "" КОНЕЦ КАК Состав
ИЗ
    Документ.РеализацияТоваровУслуг КАК Док
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК ТЧ1
        ПО Док.Ссылка = ТЧ1.Ссылка И ТЧ1.НомерСтроки = 1
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК ТЧ2
        ПО Док.Ссылка = ТЧ2.Ссылка И ТЧ2.НомерСтроки = 2

Преимущества: Работает "из коробки" в динамическом списке без написания кода на языке 1С.

Недостатки: Резкое падение производительности при увеличении количества соединений. Невозможность вывести произвольное количество строк (динамический список начнет дублировать строки, если не ограничивать НомерСтроки).

Итоги и рекомендации

Мы рассмотрели три принципиально разных подхода к решению задачи. Выбор метода зависит от ваших приоритетов:

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

Помните, что динамический список предназначен для быстрого отображения порций данных. Любое усложнение его основного запроса или добавление тяжелых вычислений в события отрисовки напрямую влияет на комфорт работы пользователя.

← На главную