Разработчики, переходящие с версии 1С 8.3 на старые конфигурации версии 8.1, часто сталкиваются с отсутствием привычного объекта ДинамическийСписок. В управляемых формах этот объект позволяет легко прописать произвольный SQL-подобный запрос, добавить расчетные поля и сложные соединения. Однако в версии 8.1 объекты типа ДокументСписок или СправочникСписок жестко привязаны к соответствующим таблицам базы данных, и напрямую изменить их текст запроса невозможно.
В этой статье мы подробно разберем, как обойти это ограничение, проанализируем доступные инструменты платформы 8.1 и выберем оптимальные методики для создания сложных списков с расчетными данными.
Это самый гибкий способ, который позволяет полностью контролировать состав данных. Мы подготавливаем запрос любой сложности, выгружаем результат в ТаблицаЗначений и отображаем её в ТабличноеПоле на форме. Рассмотрим этот процесс подробнее.
Преимущества: Полная свобода в написании запроса, использование итогов, соединений и расчетных полей любой сложности.
Недостатки: Отсутствие динамической подгрузки данных. Если в выборке будут десятки тысяч строк, форма будет открываться крайне медленно, а оперативная память клиента — переполняться.
Проанализируем алгоритм реализации:
ТабличноеПоле и в качестве типа значения выбираем ТаблицаЗначений.Посмотрим на пример кода для заполнения такой таблицы:
Процедура ОбновитьСписок()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Ссылка,
| РеализацияТоваровУслуг.Дата КАК Дата,
| РеализацияТоваровУслуг.Номер КАК Номер,
| РеализацияТоваровУслуг.Контрагент КАК Контрагент,
| ВЫБОР КОГДА РеализацияТоваровУслуг.СуммаДокумента > 100000
| ТОГДА ""Крупный"" ИНАЧЕ ""Обычный"" КОНЕЦ КАК Категория
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг";
РезультатЗапроса = Запрос.Выполнить();
ТаблицаНаФорме = РезультатЗапроса.Выгрузить();
// Передаем данные в элемент управления на форме
ЭлементыФормы.ТабличноеПолеДанные.Значение = ТаблицаНаФорме;
ЭлементыФормы.ТабличноеПолеДанные.СоздатьКолонки();
КонецПроцедуры
Чтобы данные были актуальными, вызовем эту процедуру при открытии формы или по обработчику оповещения, если данные в базе изменились.
Если нам нужно оставить стандартный объект ДокументСписок (чтобы работали стандартные отборы, сортировки и динамическая порционная подгрузка данных), но при этом добавить в него «виртуальные» или расчетные поля, нам следует использовать событие ПриПолученииДанных.
Важное уточнение: Многие начинающие программисты используют событие ПриВыводеСтроки. Это большая ошибка для производительности, так как это событие вызывается для каждой строки отдельно. Если внутри него делать запрос к базе, вы получите классическую проблему "N+1 запрос", что приведет к "тормозам" при прокрутке списка.
Разберем правильный подход с использованием ПриПолученииДанных. Это событие получает сразу массив строк, которые видны пользователю на экране в данный момент.
Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
// Собираем все ссылки на документы, которые видны на экране
МассивСсылок = Новый Массив;
СоответствиеСтрок = Новый Соответствие;
Для Каждого Оформление Из ОформленияСтрок Цикл
МассивСсылок.Добавить(Оформление.ДанныеСтроки.Ссылка);
СоответствиеСтрок.Вставить(Оформление.ДанныеСтроки.Ссылка, Оформление);
EndЦикла;
// Выполняем ОДИН запрос ко всем видимым объектам
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДополнительныеСведения.Объект КАК Ссылка,
| ДополнительныеСведения.Значение КАК СтатусОплаты
|ИЗ
| РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
|ГДЕ
| ДополнительныеСведения.Объект В(&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
Выборка = Запрос.Выполнить().Выбрать();
// Распределяем полученные данные по ячейкам оформления строк
Пока Выборка.Следующий() Цикл
Оформление = СоответствиеСтрок.Получить(Выборка.Ссылка);
Если Оформление <> Неопределено Тогда
Оформление.Ячейки.СтатусОплаты.УстановитьТекст(Строка(Выборка.СтатусОплаты));
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот метод позволяет имитировать динамический список 8.3, сохраняя высокую скорость работы интерфейса даже на огромных таблицах.
Иногда задача стоит так: «Покажите мне в стандартном списке документов только те, которые удовлетворяют сложному условию (например, по остаткам на складах)». В 8.1 стандартный ДокументСписок не умеет соединяться с регистрами остатков в реальном времени.
Рассмотрим прием «Предварительная выборка». Мы сначала программно выполняем сложный запрос, получаем список ссылок, а затем накладываем фильтр на стандартный ДокументСписок.
Проанализируем шаги:
Ссылка.СписокЗначений.ДокументСписок по виду сравнения ВСписке.
// Пример установки сложного фильтра
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Документ.ЗаказПокупателя ГДЕ СуммаДокумента > 50000");
СписокСсылок = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
ДокументСписок.Отбор.Ссылка.Использовать = Истина;
ДокументСписок.Отбор.Ссылка.ВидСравнения = ВидСравнения.ВСписке;
ДокументСписок.Отбор.Ссылка.Значение.ЗагрузитьЗначения(СписокСсылок);
Внимание: У этого метода есть ограничение со стороны СУБД (например, MS SQL Server). Если список ссылок будет содержать десятки тысяч элементов, запрос платформы к базе данных может стать слишком длинным и вызвать ошибку переполнения параметров SQL.
Мало кто помнит, но в 1С 8.1 уже была СКД. Хотя её чаще использовали для отчетов, мы можем создать схему компоновки, результат которой будет выводиться в ПолеТабличногоДокумента или ТабличноеПоле прямо на форме.
Этот способ максимально приближен к «Динамическому списку» 8.3 по своей идеологии, так как СКД берет на себя построение запроса, отборы и группировки. Однако реализация интерактивности (открытие формы документа по клику) в 8.1 для СКД потребует ручного написания кода в событии Выбор.
Выбор решения зависит от объема данных и требований к интерфейсу:
ТаблицаЗначений, но не забывайте добавлять фильтры по периоду, чтобы не перегружать память.ДокументСписок и событие ПриПолученииДанных для отображения дополнительных колонок.Таким образом, несмотря на отсутствие прямого аналога ДинамическийСписок в 1С 8.1, комбинирование вышеуказанных методов позволяет решать практически любые технические задачи по отображению данных в обычных формах.