В конфигурациях 1С на обычных формах (например, в 1С:Комплексная автоматизация 1.1 или Управление производственным предприятием 1.3) разработчики часто сталкиваются с задачей отобразить в форме списка документов дополнительную информацию из связанных справочников. Типичный пример — показ группы (родителя), в которой находится контрагент из документа.
Попытка просто выбрать в свойствах добавленной колонки реквизит через точку (Контрагент.Родитель) не увенчается успехом: объект ДокументСписок обычных форм, в отличие от динамических списков управляемого приложения с произвольным запросом, не поддерживает прямую адресацию к полям через точку. Свойство Данные у добавленной колонки табличного поля должно оставаться пустым, а заполнять ячейки необходимо программно.
Разберем по шагам, как правильно реализовать эту задачу, выясним причину возможных проблем с производительностью и рассмотрим оптимальный код заполнения.
Для динамического заполнения ячеек списка используется обработчик события таблицы ПриПолученииДанных. Платформа вызывает его в тот момент, когда порция строк уже получена из базы данных и подготавливается к отображению на экране.
В простейшем варианте, предложенном на форуме, выполняется обход строк и непосредственное чтение реквизита через точку:
Процедура ДокументСписокПриПолученииДанных(Элемент, ОформленияСтрок)
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
ОформлениеСтроки.Ячейки.Родитель.УстановитьТекст(ОформлениеСтроки.ДанныеСтроки.Контрагент.Родитель);
КонецЦикла;
КонецПроцедуры
Проанализируем этот код. Он действительно выводит нужный текст в ячейку колонки с именем Родитель. Однако у такой реализации есть критический недостаток, о котором необходимо знать.
Выясним причину падения скорости работы интерфейса при таком подходе. Конструкция ОформлениеСтроки.ДанныеСтроки.Контрагент.Родитель приводит к неявному обращению к базе данных для каждой строки списка. Если на экране одновременно отображается 30 документов, платформа выполнит 30 отдельных обращений к СУБД только для отрисовки родительской папки.
При быстрой прокрутке списка колесиком мыши, изменении размеров формы или обновлении списка документов форма начнет заметно «зависать» и тормозить интерфейс пользователя. Поэтому в высоконагруженных базах прямое обращение через точку в цикле оформления строк применять крайне не рекомендуется.
Чтобы избежать многократных обращений к базе данных, применим классический паттерн пакетной выборки. Рассмотрим правильный алгоритм реализации:
ОформленияСтрок соберем массив уникальных ссылок на контрагентов, присутствующих на экране.Соответствие, где ключом будет ссылка на контрагента, а значением — ссылка на его родителя.Посмотрим на пример оптимального кода обработчика:
Процедура ДокументСписокПриПолученииДанных(Элемент, ОформленияСтрок)
// Шаг 1. Собираем массив контрагентов из видимых строк
МассивКонтрагентов = Новый Массив;
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
ТекКонтрагент = ОформлениеСтроки.ДанныеСтроки.Контрагент;
Если ЗначениеЗаполнено(ТекКонтрагент) Тогда
МассивКонтрагентов.Добавить(ТекКонтрагент);
КонецЕсли;
КонецЦикла;
Если МассивКонтрагентов.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// Шаг 2. Выполняем один запрос к базе данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.Родитель КАК Родитель
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.Ссылка В (&МассивКонтрагентов)";
Запрос.УстановитьПараметр("МассивКонтрагентов", МассивКонтрагентов);
// Шаг 3. Сохраняем результат в соответствие
Выборка = Запрос.Выполнить().Выбрать();
СоответствиеРодителей = Новый Соответствие;
Пока Выборка.Следующий() Цикл
СоответствиеРодителей.Вставить(Выборка.Ссылка, Выборка.Родитель);
КонецЦикла;
// Шаг 4. Заполняем ячейки таблицы
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
НайденныйРодитель = СоответствиеРодителей[ОформлениеСтроки.ДанныеСтроки.Контрагент];
Если НайденныйРодитель <> Неопределено Тогда
ОформлениеСтроки.Ячейки.Родитель.Значение = НайденныйРодитель;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Обратите внимание на строку ОформлениеСтроки.Ячейки.Родитель.Значение = НайденныйРодитель;. В отличие от метода УстановитьТекст(), присвоение ссылки напрямую в свойство Значение позволяет платформе не просто вывести строковое наименование, но и автоматически отобразить стандартную пиктограмму папки справочника.
Рассмотрим важные особенности поведения добавленной колонки, о которых нужно предупредить пользователей:
ДокументСписок.Если задача добавления колонки заключалась в фильтрации документов по группам контрагентов, создавать отдельную колонку необязательно. В панели отборов формы списка можно использовать штатный отбор по полю Контрагент с видом сравнения В иерархии или В списке по иерархии.
Если же сортировка и быстрый отбор по родителю критически необходимы для бизнес-процесса, единственным решением для обычных форм будет денормализация: добавление реквизита РодительКонтрагента непосредственно в сам документ и его автоматическое заполнение при выборе контрагента или перед записью документа.