Как программно настроить отбор через КомпоновщикНастроек и вывести результат СКД в таблицу значений?

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача предоставить пользователю гибкий интерфейс для настройки отборов по данным информационной базы (подобно отчетам СКД), но результат обработки вывести не в табличный документ, а в программную коллекцию — ТаблицаЗначений или реквизит формы. При реализации этого сценария разработчики нередко сталкиваются с ситуацией, когда инициализированный макет компоновки возвращает пустую таблицу или элементы отбора на форме работают некорректно.

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

Причины формирования пустой таблицы при программном выводе СКД

Проанализируем основные причины, по которым процессор вывода может возвращать пустую таблицу значений даже при наличии данных в информационной базе:

  1. Отсутствие группировок в структуре настроек. При использовании объекта ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений критически важно, чтобы в коллекции Структура передаваемых настроек присутствовала хотя бы одна группировка (например, детальные записи). Если структура пуста, компоновщик не создает узлы данных, и вывод завершается без ошибок, но с пустой таблицей.
  2. Не установлены выбранные поля. Если в схеме компоновки задан запрос с конструкцией ВЫБРАТЬ *, СКД оптимизирует исполнение и включает в результирующий запрос только те поля, которые явно указаны в коллекции ВыбранныеПоля группировки или настроек. Без выбранных полей выборка не вернет строк.
  3. Некорректная передача настроек в компоновщик макета. Если пользователь настраивает фильтры через пользовательские настройки, использование метода Компоновщик.ПолучитьНастройки() гарантирует получение результирующих настроек с учетом всех интерактивных изменений. Если же отбор менялся напрямую в свойстве Настройки, вызов ПолучитьНастройки() может вернуть базовое состояние без изменений. В таком случае следует передавать свойство Компоновщик.Настройки напрямую.

Инициализация компоновщика настроек на управляемой форме

Рассмотрим, как правильно связать реквизит формы типа КомпоновщикНастроекКомпоновкиДанных с макетом схемы компоновки данных. На управляемых формах контекст схемы должен передаваться через временное хранилище с созданием объекта ИсточникДоступныхНастроекКомпоновкиДанных.

Разберем реализацию в обработчике создания формы:


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

Для отображения отбора пользователю на форму добавляется таблица, свойство ПутьКДанным которой связывается либо с КомпоновщикНастроек.Настройки.Отбор, либо с КомпоновщикНастроек.ПользовательскиеНастройки.

Программное получение таблицы значений через ПроцессорВывода

Посмотрим на стандартный механизм вывода результата компоновки в ТаблицаЗначений. Этот способ полностью задействует механизм СКД, включая вычисляемые поля, пользовательские поля и условное оформление:


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

Альтернативный вариант: выполнение сгенерированного запроса

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

Рассмотрим пример реализации:


&НаСервере
Функция ВыполнитьСгенерированныйЗапросСКД()
    
    ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
    Схема = ОбработкаОбъект.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, КомпоновщикНастроек.ПолучитьНастройки());
    
    // Извлекаем текст запроса первого набора данных
    Запрос = Новый Запрос(МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос);
    
    // Переносим значения параметров, сгенерированных компоновщиком
    Для Каждого ТекПараметр Из Запрос.НайтиПараметры() Цикл
        ИмяПараметра = ТекПараметр.Имя;
        Если МакетКомпоновки.ЗначенияПараметров.Найти(ИмяПараметра) <> Неопределено Тогда
            Запрос.УстановитьПараметр(ИмяПараметра, МакетКомпоновки.ЗначенияПараметров[ИмяПараметра].Значение);
        КонецЕсли;
    КонецЦикла;
    
    Возврат Запрос.Выполнить().Выгрузить();
    
КонецФункции

Восстановление настроек из базы данных

Если требуется сохранять и восстанавливать пользовательские настройки отбора (например, в регистре сведений через ХранилищеЗначений), инициализация выполняется следующим образом:


&НаСервере
Процедура ЗагрузитьСохраненныеНастройки(СохраненныеНастройки)
    
    Если ТипЗнч(СохраненныеНастройки) = Тип("НастройкиКомпоновкиДанных") Тогда
        // Загружаем настройки напрямую в компоновщик
        КомпоновщикНастроек.ЗагрузитьНастройки(СохраненныеНастройки);
    КонецЕсли;
    
КонецПроцедуры

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

← На главную