Как получить данные динамического списка с учетом пользовательских отборов

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

При разработке интерфейсов на управляемых формах 1С программисты часто сталкиваются с задачей обработки данных, которые пользователь видит на экране в данный момент. Особенность объекта ДинамическийСписок заключается в том, что он не хранит все данные в оперативной памяти (в отличие от таблицы значений), а подгружает их порциями из базы данных. Если пользователь воспользовался поиском (Ctrl+F), установил отбор через «Найти» или настроил сложный фильтр в окне настроек списка, нам может потребоваться программно получить именно этот «отфильтрованный» набор строк — например, чтобы подсчитать их количество или выполнить над ними групповое действие.

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

Основы механизма: Исполняемая схема компоновки

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

Рассмотрим основные методы, которые нам понадобятся:

  1. ПолучитьИсполняемуюСхемуКомпоновкиДанных() — возвращает объект СхемаКомпоновкиДанных, содержащую текст запроса и описание полей.
  2. ПолучитьИсполняемыеНастройкиКомпоновкиДанных() — возвращает текущие НастройкиКомпоновкиДанных, в которых объединены пользовательские фильтры, фиксированные отборы и параметры поиска.

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

Способ №1: Получение данных в таблицу значений через Процессор компоновки

Проанализируем наиболее универсальный подход. Он позволяет получить результат в виде таблицы значений, полностью повторяющей структуру и данные списка с учетом всех фильтров. Это удобно, если строк немного (например, до нескольких тысяч) и вам нужно обработать каждое значение.

Рассмотрим программный код реализации этого метода:


&НаСервере
Процедура ПолучитьДанныеСпискаНаСервере()
    
    // 1. Получаем схему и настройки из элемента формы (динамического списка)
    // Предположим, что основной реквизит списка на форме называется "Список"
    Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
    Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
    
    // 2. Подготавливаем макет компоновки
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    // Указываем тип генератора для выгрузки в коллекцию (таблицу значений)
    ТипГенератора = Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений");
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , ТипГенератора);
    
    // 3. Инициализируем процессор компоновки данными макета
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
    
    // 4. Выводим результат в таблицу значений
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    РезультатТаблица = Новый ТаблицаЗначений;
    ПроцессорВывода.УстановитьОбъект(РезультатТаблица);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    // Теперь переменная РезультатТаблица содержит все строки, которые видел пользователь
    КоличествоСтрок = РезультатТаблица.Количество();
    Сообщить("Выбрано строк: " + КоличествоСтрок);
    
КонецПроцедуры

Этот метод хорош тем, что он автоматически учитывает права доступа (RLS), функциональные опции и параметры запроса. Однако помните о производительности: если в отбор попадет 100 000 записей, выгрузка их всех в таблицу значений может привести к переполнению памяти сервера.

Способ №2: Оптимизированный подсчет количества или прямой запрос

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

Посмотрим на пример кода, который позволяет выполнить запрос напрямую:


&НаСервере
Функция ПолучитьКоличествоЗаписейСписка()
    
    Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
    Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки);
    
    // Получаем текст запроса, который сформировала система компоновки
    ТекстЗапроса = МакетКомпоновки.НаборыДанных[0].Запрос;
    
    // Если нам нужно только количество, мы можем обернуть этот запрос
    ТекстЗапросаКоличество = "ВЫБРАТЬ КОЛИЧЕСТВО(*) ИЗ (" + ТекстЗапроса + ") КАК Подзапрос";
    
    Запрос = Новый Запрос(ТекстЗапросаКоличество);
    
    // Важно передать все параметры, которые СКД сформировала для отборов и поиска
    Для Каждого Параметр Из МакетКомпоновки.ЗначенияПараметров Цикл
        Запрос.УстановитьПараметр(Параметр.Имя, Параметр.Значение);
    КонецЦикла;
    
    Результат = Запрос.Выполнить();
    Если Не Результат.Пустой() Тогда
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        Возврат Выборка[0];
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

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

Важные технические нюансы

Проанализируем несколько критических моментов, о которых стоит помнить при работе с этими методами:

  1. Различие между Поиском и Отбором: Когда пользователь вводит текст в строку поиска, платформа 1С трансформирует это в сложные условия ПОДОБНО для всех видимых текстовых полей. Метод ПолучитьИсполняемыеНастройки корректно собирает эти условия. Однако в старых версиях платформы поиск через Ctrl+F мог не всегда попадать в настройки. В современных релизах (8.3.10+) эта проблема решена.
  2. Произвольные запросы и Основная таблица: Если ваш динамический список построен не на произвольном запросе, а на основной таблице, система генерирует текст запроса автоматически. В макете компоновки вы увидите программно сгенерированные имена полей (например, П1, Поле1). Будьте внимательны при обращении к полям в результирующей таблице.
  3. Ограничения доступа (RLS): Одним из главных преимуществ использования ПолучитьИсполняемуюСхемуКомпоновкиДанных является то, что она учитывает права доступа пользователя «на уровне записей». Если вы просто напишете свой запрос к той же таблице, вы можете получить больше данных, чем видит пользователь, что приведет к ошибкам в логике программы.
  4. Постраничная обработка: Если данных очень много, вместо выгрузки в таблицу значений (ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений) используйте ПроцессорКомпоновкиДанных.ОткрытьРезультат(). Это позволит обходить записи по одной с помощью метода Следующий(), не загружая их все одновременно в память.

Заключение

Мы рассмотрели эффективные способы программного доступа к данным динамического списка. Использование исполняемой схемы компоновки — это единственный надежный способ узнать, что именно видит пользователь в данный момент с учетом всех фильтров, поиска и ограничений прав. Выбор между использованием процессора вывода и прямым выполнением запроса зависит от вашей конкретной задачи: нужен ли вам полный набор данных или достаточно агрегатных значений (количество, сумма).

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

← На главную