В платформе 1С:Предприятие 7.7 динамические списки справочников работают по иным принципам, нежели в современной платформе 1С 8. Разработчики часто сталкиваются с задачей отображения общего количества строк в форме списка, особенно после того, как пользователь наложил определенный фильтр. Вывод этой информации позволяет пользователю оценить объем выборки для дальнейшей интерактивной или групповой обработки.
В рамках этой статьи мы подробно рассмотрим, как решить задачу подсчета количества записей. Мы проанализируем различные сценарии — от простейшего штатного отбора по списку значений до низкоуровневых оптимизированных решений с использованием прямых SQL-запросов и внешних компонент.
Если в вашей конфигурации отбор накладывается программно с использованием предопределенного списка элементов, то задача подсчета количества строк решается тривиально. Метод ИспользоватьСписокЭлементов принимает в качестве параметра объект типа СписокЗначений, который уже содержит строго определенный массив элементов.
Давайте рассмотрим по шагам, как получить размер этого списка:
// Создаем список значений для фильтрации
СписокДляФильтра = СоздатьОбъект("СписокЗначений");
// Заполняем список нужными элементами (например, элементами определенной группы)
СпрНоменклатура = СоздатьОбъект("Справочник.Номенклатура");
СпрНоменклатура.ВыбратьЭлементы();
Пока СпрНоменклатура.ПолучитьЭлемент() = 1 Цикл
Если СпрНоменклатура.РеквизитОтбора = ВыбЗначение Тогда
СписокДляФильтра.ДобавитьЗначение(СпрНоменклатура.ТекущийЭлемент());
КонецЕсли;
КонецЦикла;
// Накладываем фильтр на форму списка
ИспользоватьСписокЭлементов(СписокДляФильтра);
// Получаем точное количество строк на форме
КоличествоЗаписей = СписокДляФильтра.РазмерСписка();
Предупреждение("Количество показанных элементов: " + КоличествоЗаписей);
Этот способ надежен и прост, однако он применим только тогда, когда фильтр накладывается разработчиком принудительно через программный код, а не силами самого пользователя через интерфейс.
Ситуация усложняется, если отбор в форме списка накладывается методом УстановитьОтбор. Стандартный механизм динамического списка 1С 7.7 не предоставляет разработчику свойства вроде КоличествоСтрок() для формы списка справочника. Если запустить перебор элементов справочника в цикле через ВыбратьЭлементы() с установленным фильтром, это приведет к серьезным задержкам (интерфейс «зависнет» на больших базах).
Выясним причину: при обычном обходе выборки платформа последовательно считывает каждую запись с диска в оперативную память. Чтобы оптимизировать этот процесс, мы можем задействовать штатный механизм запросов 1С. Запросы обрабатываются ядром СУБД гораздо эффективнее. При этом мы используем встроенную функцию Счетчик().
Проанализируем пример реализации такого подсчета:
Функция ПолучитьКоличествоЭлементовСОтбором(ИмяРеквизита, ЗначениеРеквизита) Экспорт
Запрос = СоздатьОбъект("Запрос");
// Формируем текст запроса с агрегатной функцией Счетчик()
ТекстЗапроса =
"|Текущий = Справочник.Номенклатура.ТекущийЭлемент;
|Реквизит = Справочник.Номенклатура." + ИмяРеквизита + ";
|Функция КолВо = Счетчик();
|Условие(Реквизит = ЗначениеРеквизита);";
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
Возврат Запрос.КолВо;
Иначе
Возврат 0;
EndIf;
КонецФункции
Этот код работает на порядок быстрее, чем пообъектный обход справочника, и возвращает точное количество элементов, удовлетворяющих заданному критерию.
Если ваша база данных 1С 7.7 развернута на Microsoft SQL Server, то самым быстрым и современным решением будет отправка прямого SQL-запроса в обход стандартного движка DB-Engines платформы. Для этого используется внешняя компонента 1С++ и класс ODBCRecordset.
Давайте разберем этот процесс подробно. Прямой запрос считает количество записей на уровне SQL Server за миллисекунды, даже если в справочнике содержатся миллионы элементов. Нам понадобится метаописание таблицы справочника, которое компонента подставляет автоматически при использовании конструкции со знаком доллара $.
Посмотрим на пример кода:
// Создаем объект для прямого доступа к базе SQL
ЗапросSQL = СоздатьОбъект("ODBCRecordset");
// Подготавливаем текст запроса
// $Справочник.Номенклатура - автоподстановка имени таблицы СУБД
// $Справочник.Номенклатура.ВидНоменклатуры - автоподстановка имени колонки реквизита
ТекстЗапроса = "
|SELECT COUNT(ID) as TotalCount
|FROM $Справочник.Номенклатура (NOLOCK)
|WHERE $Справочник.Номенклатура.ВидНоменклатуры = :ВыбВид
| AND IsFolder = 3
|";
ЗапросSQL.УстановитьТекстовыйПараметр("ВыбВид", ВыбранныйВидНоменклатуры);
// Выполняем запрос
ТабРезультата = ЗапросSQL.ВыполнитьИнструкцию(ТекстЗапроса);
КоличествоЗаписей = ТабРезультата.ПолучитьЗначение(1, "TotalCount");
Предупреждение("Количество отфильтрованных элементов (SQL): " + КоличествоЗаписей);
Обратите внимание на конструкцию IsFolder = 3. В физической структуре таблиц 1С 7.7 это условие означает выборку только элементов (не групп). Если вам нужно посчитать и группы тоже, это условие следует скорректировать.
Иногда требуется мгновенно узнать общее количество записей в справочнике без фильтрации, когда база данных работает в файловом режиме (DBF). Стандартный метод ВыбратьЭлементы() заставит систему сканировать таблицу. Но есть обходной путь — прочитать физические параметры DBF-файла.
Каждая таблица справочника хранится в файле с именем SC*.dbf (номер можно узнать в конфигураторе или программно через метаданные). Структура заголовка DBF-файла строго регламентирована стандартом dBase III:
Зная это, мы можем считать заголовок файла напрямую с диска, используя объект ФС (Файловая система) или специализированные внешние компоненты для работы с бинарными файлами, и мгновенно извлечь количество строк. Однако важно помнить: этот метод вернет общее количество записей, включая те, которые помечены в СУБД как удаленные (но физически еще не стертые процедурой «Упаковка таблиц»).
Для создания действительно отзывчивых интерфейсов опытные разработчики 1С 7.7 полностью отказываются от стандартных форм списков. С помощью связки внешних компонент 1С++ и FormEx на форму помещается элемент управления «ТабличноеПоле» (Grid).
В этом случае вывод данных полностью контролируется программным кодом:
ТаблицуЗначений.ТаблицаДанных.КоличествоСтрок() и выводится в статус-бар или текстовое поле формы.Этот подход требует больше времени на проектирование и написание кода, но предоставляет неограниченные возможности кастомизации интерфейса и гарантирует максимальное быстродействие системы.