В процессе разработки интерфейсов на платформе 1С:Предприятие 8.3 часто возникает задача отображения общего количества записей в динамическом списке. Это особенно актуально для форм списков документов или справочников, где пользователю важно понимать объем данных, попадающих под установленные им фильтры. В этой статье мы подробно разберем, как реализовать такой механизм, учитывая технические нюансы работы с ДинамическимСписком и Системой компоновки данных (СКД).
Для начала проанализируем, почему задача не решается простым обращением к свойству списка. Динамический список — это объект, предназначенный для порционного отображения данных. Он не считывает всю таблицу целиком ради экономии ресурсов, поэтому «из коробки» не знает общего количества записей, соответствующих текущим отборам. Чтобы получить эту цифру, нам необходимо заставить платформу сформировать запрос, который она бы выполнила для получения данных, и модифицировать его для подсчета количества.
Рассмотрим наиболее профессиональный и точный подход. Начиная с определенных версий платформы 8.3, у динамического списка появились методы, позволяющие «вытащить» его внутреннюю логику запроса. Разберем по шагам, как это реализовать на сервере.
Для получения количества нам потребуются методы ПолучитьИсполняемуюСхемуКомпоновкиДанных() и ПолучитьИсполняемыеНастройкиКомпоновкиДанных(). Эти методы возвращают схему и настройки, в которых уже учтены все пользовательские отборы, параметры и даже фиксированные настройки, заданные программистом.
Алгоритм действий на сервере:
Список.КОЛИЧЕСТВО(*).Посмотрим на пример кода, реализующего эту логику:
&НаСервере
Функция ПолучитьКоличествоЗаписейНаСервере()
// Получаем схему и настройки динамического списка
Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
// Модифицируем схему для подсчета количества
// Нам нужно заменить текст основного запроса
Для Каждого ИсточникДанных Из Схема.ИсточникиДанных Цикл
// Здесь можно программно изменить текст запроса, заменив SELECT на SELECT COUNT(*)
КонецЦикла;
// Используем компоновщик макета для генерации финального запроса
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки,,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// Выполняем запрос
Запрос = Новый Запрос;
Запрос.Текст = МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос;
// Передаем параметры из макета в запрос
Для Каждого Параметр Из МакетКомпоновки.ЗначенияПараметров Цикл
Запрос.УстановитьПараметр(Параметр.Имя, Параметр.Значение);
КонецЦикла;
// Оборачиваем запрос для получения количества
Запрос.Текст = "ВЫБРАТЬ КОЛИЧЕСТВО(*) КАК Всего ИЗ (" + Запрос.Текст + ") КАК ВложенныйЗапрос";
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Всего;
КонецЕсли;
Возврат 0;
КонецФункции
Выясним важную причину, по которой стандартный метод СКД может возвращать не совсем точные данные. Существует так называемый «быстрый поиск» (строка поиска в верхней части списка). К сожалению, строка, введенная пользователем через Ctrl+F, часто не попадает в коллекцию Отбор компоновщика настроек. Платформа обрабатывает полнотекстовый поиск на уровне внутренних механизмов СУБД или индекса поиска.
На текущий момент прямого способа программно получить количество записей с учетом именно строки поиска (если это не программный фильтр) без существенных потерь производительности не существует. Поэтому стоит информировать пользователей, что счетчик обновляется только при использовании стандартных отборов.
Проанализируем ситуацию: если в базе миллионы документов, выполнение агрегатного запроса COUNT при каждом изменении фильтра может привести к тому, что интерфейс станет «тяжелым». Чтобы этого избежать, применим несколько хитростей:
ПодключитьОбработчикОжидания на 1-2 секунды.ПриОбновленииСоставаДанныхВсе на клиенте. Это событие срабатывает, когда состав данных в списке меняется (применили фильтр, добавили документ).Пример клиентского кода:
&НаКлиенте
Процедура СписокПриОбновленииСоставаДанныхВсе(Элемент)
// Отменяем предыдущий вызов, если пользователь продолжает менять фильтры
ОтключитьОбработчикОжидания("ОбновитьСчетчикЗаписей");
// Запускаем расчет с небольшой задержкой
ПодключитьОбработчикОжидания("ОбновитьСчетчикЗаписей", 1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьСчетчикЗаписей()
КоличествоЗаписей = ПолучитьКоличествоЗаписейНаСервере();
Элементы.ДекорацияКоличество.Заголовок = "Записей в списке: " + КоличествоЗаписей;
КонецПроцедуры
Разберем ситуацию с мобильной платформой. Как было отмечено в обсуждении, в мобильном приложении (не путать с мобильным клиентом) работа с методами ПолучитьИсполняемуюСхемуКомпоновкиДанных может быть ограничена или недоступна. В этом случае программисту приходится вручную обходить коллекцию Список.КомпоновщикНастроек.Настройки.Отбор, рекурсивно анализировать группы «И/ИЛИ» и программно собирать условие ГДЕ для обычного запроса.
Это трудоемкий процесс, требующий обработки всех видов сравнения (Равно, В списке, Содержит и т.д.). Однако для большинства типовых конфигураций на управляемых формах стандартный метод через исполняемую схему СКД является эталонным.
Мы рассмотрели основной способ реализации подсчета записей в динамическом списке. Главное помнить, что динамический список — это не таблица значений, и получение его параметров требует обращения к механизмам компоновки данных. Правильное сочетание серверных вызовов, методов СКД и клиентских обработчиков ожидания позволит вам создать отзывчивый и информативный интерфейс для пользователей 1С.