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

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

В конфигурациях 1С на обычных формах (например, в 1С:Комплексная автоматизация 1.1 или Управление производственным предприятием 1.3) разработчики часто сталкиваются с задачей отобразить в форме списка документов дополнительную информацию из связанных справочников. Типичный пример — показ группы (родителя), в которой находится контрагент из документа.

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

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

Базовый способ: использование события ПриПолученииДанных

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

В простейшем варианте, предложенном на форуме, выполняется обход строк и непосредственное чтение реквизита через точку:


Процедура ДокументСписокПриПолученииДанных(Элемент, ОформленияСтрок)
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        ОформлениеСтроки.Ячейки.Родитель.УстановитьТекст(ОформлениеСтроки.ДанныеСтроки.Контрагент.Родитель);
    КонецЦикла;
КонецПроцедуры

Проанализируем этот код. Он действительно выводит нужный текст в ячейку колонки с именем Родитель. Однако у такой реализации есть критический недостаток, о котором необходимо знать.

Анализ проблемы производительности: почему нельзя обращаться через точку в цикле

Выясним причину падения скорости работы интерфейса при таком подходе. Конструкция ОформлениеСтроки.ДанныеСтроки.Контрагент.Родитель приводит к неявному обращению к базе данных для каждой строки списка. Если на экране одновременно отображается 30 документов, платформа выполнит 30 отдельных обращений к СУБД только для отрисовки родительской папки.

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

Оптимальное решение: пакетная выборка данных одним запросом

Чтобы избежать многократных обращений к базе данных, применим классический паттерн пакетной выборки. Рассмотрим правильный алгоритм реализации:

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

Посмотрим на пример оптимального кода обработчика:


Процедура ДокументСписокПриПолученииДанных(Элемент, ОформленияСтрок)
    // Шаг 1. Собираем массив контрагентов из видимых строк
    МассивКонтрагентов = Новый Массив;
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        ТекКонтрагент = ОформлениеСтроки.ДанныеСтроки.Контрагент;
        Если ЗначениеЗаполнено(ТекКонтрагент) Тогда
            МассивКонтрагентов.Добавить(ТекКонтрагент);
        КонецЕсли;
    КонецЦикла;

    Если МассивКонтрагентов.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

    // Шаг 2. Выполняем один запрос к базе данных
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |   Контрагенты.Ссылка КАК Ссылка,
        |   Контрагенты.Родитель КАК Родитель
        |ИЗ
        |   Справочник.Контрагенты КАК Контрагенты
        |ГДЕ
        |   Контрагенты.Ссылка В (&МассивКонтрагентов)";
    Запрос.УстановитьПараметр("МассивКонтрагентов", МассивКонтрагентов);

    // Шаг 3. Сохраняем результат в соответствие
    Выборка = Запрос.Выполнить().Выбрать();
    СоответствиеРодителей = Новый Соответствие;
    Пока Выборка.Следующий() Цикл
        СоответствиеРодителей.Вставить(Выборка.Ссылка, Выборка.Родитель);
    КонецЦикла;

    // Шаг 4. Заполняем ячейки таблицы
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        НайденныйРодитель = СоответствиеРодителей[ОформлениеСтроки.ДанныеСтроки.Контрагент];
        Если НайденныйРодитель <> Неопределено Тогда
            ОформлениеСтроки.Ячейки.Родитель.Значение = НайденныйРодитель;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Обратите внимание на строку ОформлениеСтроки.Ячейки.Родитель.Значение = НайденныйРодитель;. В отличие от метода УстановитьТекст(), присвоение ссылки напрямую в свойство Значение позволяет платформе не просто вывести строковое наименование, но и автоматически отобразить стандартную пиктограмму папки справочника.

Ограничения вычисляемых колонок в обычных формах

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

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

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

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

← На главную