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

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

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

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

Постановка задачи и специфика данных

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

Поскольку форма списка построена на базе механизма Динамический список, стандартного обращения через точку к реквизитам табличной части (как к реквизитам шапки) у нас нет. Нам потребуется изменить схему запроса динамического списка.

---

Способ 1. Левое соединение в запросе динамического списка (Быстрое решение)

Самый очевидный и быстрый способ, предложенный участниками обсуждения, — это перевести динамический список в режим использования произвольного запроса и связать основную таблицу документа с таблицей его табличной части посредством левого соединения (LEFT JOIN).

Для реализации этого способа выполним следующие шаги:

  1. Откроем форму списка документов в конфигураторе.
  2. Перейдем в свойства свойства элемента Список (тип: ДинамическийСписок).
  3. Установим флаг Произвольный запрос.
  4. Откроем конструктор запроса или отредактируем текст запроса вручную.

Рассмотрим по шагам оптимальный вариант запроса без использования лишних вложенных запросов и параметров:


ВЫБРАТЬ
    ДанныеДокумента.Ссылка КАК Ссылка,
    ДанныеДокумента.ПометкаУдаления КАК ПометкаУдаления,
    ДанныеДокумента.Номер КАК Номер,
    ДанныеДокумента.Дата КАК Дата,
    ДанныеДокумента.Проведен КАК Проведен,
    ДанныеДокумента.Организация КАК Организация,
    ДанныеДокумента.СуммаДокумента КАК СуммаДокумента,
    ДанныеДокумента.Валюта КАК Валюта,
    
    // Выбираем реквизит Партнер из присоединенной табличной части
    ЕСТЬNULL(ТабЧастьРасшифровка.Партнер, ЗНАЧЕНИЕ(Справочник.Партнеры.ПустаяСсылка)) КАК Партнер
ИЗ
    Документ.ПоступлениеБезналичныхДенежныхСредств КАК ДанныеДокумента
    
    // Соединяем документ с его табличной частью по Ссылке и жесткому условию на первую строку
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеБезналичныхДенежныхСредств.РасшифровкаПлатежа КАК ТабЧастьРасшифровка
        ПО ДанныеДокумента.Ссылка = ТабЧастьРасшифровка.Ссылка
        И ТабЧастьРасшифровка.НомерСтроки = 1

Важные особенности этого запроса:

---

В чем опасность прямого соединения с табличной частью?

Хотя первый способ прост в реализации, рассмотрим подробнее, почему опытные разработчики не рекомендуют использовать левые соединения с табличными частями в динамических списках:

  1. Проблемы производительности (Index Scan / Table Scan): На уровне СУБД для табличных частей создаются индексы по полю Ссылка. Однако составного индекса Ссылка + НомерСтроки в СУБД по умолчанию нет. При росте базы данных (сотни тысяч документов) такое соединение начнет тормозить интерфейс при прокрутке и поиске.
  2. Ограничение прав на уровне записей (RLS): Если в системе настроен RLS, платформа автоматически наложит условия ограничений прав как на основную таблицу документа, так и на присоединенную таблицу расшифровки платежа. Это может замедлить работу динамического списка в десятки раз.
  3. Риск дублирования строк: Если в условии связи будет допущена малейшая ошибка (например, упущено условие по номеру строки), СУБД вернет несколько строк табличной части на один документ. В интерфейсе пользователя это приведет к ошибке «Обнаружено дублирование ключевых значений...» либо к визуальному "размножению" одного и того же документа в списке.

---

Способ 2. Денормализация данных (Рекомендация фирмы "1С")

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

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

Выполним задачу по шагам:

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

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Заполняем реквизит шапки данными из первой строки табличной части
    Если РасшифровкаПлатежа.Количество() > 0 Тогда
        ЭтотОбъект.ОсновнойПартнер = РасшифровкаПлатежа[0].Партнер;
    Иначе
        ЭтотОбъект.ОсновнойПартнер = Справочники.Партнеры.ПустаяСсылка();
    КонецЕсли;
    
КонецПроцедуры

После этого нам достаточно просто вытащить реквизит шапки ОсновнойПартнер на форму списка документов стандартными средствами. Запрос динамического списка останется простым и быстрым, индексация будет работать корректно, а RLS не создаст лишней нагрузки на СУБД.

Обратите внимание: Для существующих в базе документов потребуется написать обработку группового перепроведения или перезаписи, которая заполнит новый реквизит ОсновнойПартнер по историческим данным.

---

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

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

Этот метод позволяет запрашивать данные из табличной части порционно — только для тех строк документов, которые в данный момент реально отображаются на экране пользователя (обычно около 30–40 строк).

Рассмотрим алгоритм настройки:

  1. В схеме запроса динамического списка добавим пустое поле-заглушку:
    
    ВЫБРАТЬ
        ДанныеДокумента.Ссылка,
        ...
        ВЫРАЗИТЬ(НЕОПРЕДЕЛЕНО КАК Справочник.Партнеры) КАК ПартнерОтображение
    ИЗ
        Документ.ПоступлениеБезналичныхДенежныхСредств КАК ДанныеДокумента
    
  2. На форме списка для таблицы списка добавим обработчик события ПриПолученииДанныхНаСервере:

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

Преимущества этого подхода:

Резюме

Мы проанализировали три метода вывода реквизитов табличной части в динамический список. Для быстрого решения "здесь и сейчас" подойдет Способ 1 с использованием левого соединения. Однако при проектировании высоконагруженных систем предпочтение всегда следует отдавать Способу 2 (денормализация) или Способу 3 (OnGetDataAtServer), так как они гарантируют стабильную и быструю работу интерфейса. Для ознакомления с другими практическими вариантами расширения состава полей можно изучить руководство по методам доработки динамических списков.

← На главную