СКД: Как сделать отбор при передаче внешней Таблицы Значений?

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

При разработке отчетов на базе Системы Компоновки Данных (СКД) в 1С мы часто сталкиваемся с необходимостью передать произвольную таблицу значений в качестве источника данных. Для этого используется НаборДанныхОбъект. Однако при настройке пользовательских отборов (например, по подразделению) разработчики часто сталкиваются с проблемой: окошко отбора выводится на форму, но список доступных значений пуст, либо фильтрация не срабатывает, и выводится полный отчет. Разберем по шагам, почему это происходит и как правильно настроить отборы для внешних наборов данных.

Кто должен делать отбор: СКД или программист?

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

  1. Отбор силами СКД (Пост-фильтрация)

    При этом подходе вы формируете программно полную таблицу значений со всеми возможными данными и передаете её целиком в СКД. Система сама, опираясь на заданные пользователем настройки, скрывает ненужные строки при компоновке результата. Это самый простой в реализации метод. Однако у него есть существенный недостаток: если ваша таблица содержит сотни тысяч строк, вы потратите значительные ресурсы сервера на формирование огромного массива данных в памяти, чтобы в итоге СКД вывела на экран лишь 5% от этого объема. Этот подход применим только для небольших объемов данных.

  2. Программный отбор (Пре-фильтрация) — рекомендуемый подход

    В этом случае мы считываем отборы, которые задал пользователь на форме, еще до того, как начнем формировать таблицу значений. Перехватив управление в обработчике ПриКомпоновкеРезультата, мы обращаемся к настройкам компоновщика, извлекаем значение отбора и применяем его на этапе сбора данных (например, передаем как параметр в наш промежуточный SQL-запрос к базе). В СКД мы передаем уже отфильтрованную, легкую таблицу. Разберем этот вариант как наиболее оптимальный с точки зрения производительности.

Почему окно отбора оказывается пустым (нет доступных значений)?

Выясним причину, по которой пользователь при попытке настроить отбор видит пустое окно без возможности выбрать элемент справочника. Когда СКД работает с обычным запросом к базе данных, она автоматически анализирует метаданные и "знает", что поле "Подразделение" имеет тип СправочникСсылка.Подразделения. На основе этого СКД сама генерирует нужную форму выбора.

Когда же мы используем тип источника НаборДанныхОбъект, мы просто перечисляем имена полей текстом. СКД по умолчанию ничего не знает о типах этих полей. Чтобы исправить эту ситуацию, настроим схему компоновки должным образом:

  1. Откройте схему компоновки данных.
  2. Перейдите на вкладку "Наборы данных".
  3. В добавленном наборе данных (объекте) найдите поле, по которому нужен отбор (например, "Подразделение").
  4. В колонке "Тип значения" явно укажите нужный тип (нажмите на кнопку выбора и отметьте галочкой СправочникСсылка.Подразделения).

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

Важность совпадения имен и типов в программном коде

Рассмотрим еще один критически важный момент. При передаче сформированной таблицы в СКД, система выполняет сопоставление данных. Если СКД не сможет сопоставить колонку из таблицы с полем в схеме, фильтры, группировки и итоги не сработают.

Обязательно проконтролируйте два правила:

  1. Имена колонок формируемой программно таблицы значений должны строго совпадать с именами полей, прописанными в настройках набора данных в СКД.
  2. Типы колонок в самой таблице значений, которую вы создаете в коде, должны соответствовать типам, указанным в схеме компоновки. Для этого при создании таблицы обязательно используйте объект ОписаниеТипов.

Посмотрим на пример правильного создания таблицы значений в коде перед её передачей в СКД:


// Создаем структуру типов для колонок таблицы
МассивТиповПодразделение = Новый Массив;
МассивТиповПодразделение.Добавить(Тип("СправочникСсылка.Подразделения"));
ОписаниеТипаПодразделение = Новый ОписаниеТипов(МассивТиповПодразделение);

МассивТиповСумма = Новый Массив;
МассивТиповСумма.Добавить(Тип("Число"));
ОписаниеТипаСумма = Новый ОписаниеТипов(МассивТиповСумма, Новый КвалификаторыЧисла(15, 2));

// Формируем саму таблицу
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Подразделение", ОписаниеТипаПодразделение);
ТаблицаДанных.Колонки.Добавить("Сумма", ОписаниеТипаСумма);

// Далее заполняем таблицу данными...

Как прочитать отбор СКД и применить его программно?

Разберем подробнее, как реализовать рекомендуемый подход (пре-фильтрацию). Нам необходимо в модуле объекта отчета переопределить стандартную компоновку и самостоятельно собрать данные. Обратимся к свойству КомпоновщикНастроек.


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

Таким образом, комбинируя явную типизацию полей в схеме компоновки и программное чтение отборов перед формированием набора данных, вы получите быстродействующий и корректно работающий отчет.

← На главную