Как сделать универсальную настройку отбора объектов программно с помощью СКД?

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

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

Постановка задачи и анализ исходного кода

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


Схема = Новый СхемаКомпоновкиДанных;
ИсточникДанных = Схема.ИсточникиДанных.Добавить();
ИсточникДанных.ТипИсточникаДанных = "Local";

НаборДанных = Схема.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
ТекстЗапроса = 
"ВЫБРАТЬ 
|   Справочник1.Ссылка КАК Ссылка 
|ИЗ 
|   Справочник.Справочник1 КАК Справочник1";

НаборДанных.Запрос = ТекстЗапроса;

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

КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, КомпоновщикНастроек.ПолучитьНастройки(),,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ТЗ = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(ТЗ);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

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

Почему в Таблицу Значений ничего не выводится?

В приведенном алгоритме есть несколько критических упущений, характерных для программной работы с СКД. Разберем по шагам, что необходимо исправить:

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

Как вытащить реально исполняемый запрос СКД?

Часто при наложении сложных отборов результаты выборки могут быть неочевидными. Запрос, который мы видим в конфигураторе (или передаем в переменной), и запрос, который реально отправляется на сервер СУБД после работы компоновщика макета — это разные вещи. Посмотрим на способы получения финального запроса:

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

2. Через «Консоль запросов и отчетов»:
Сохраните сформированную схему в XML. Откройте стандартную консоль в режиме толстого клиента, загрузите туда схему и воспользуйтесь встроенной кнопкой «Анализ исполняемых запросов результата». Это лучший инструмент для отладки условий и параметров СКД.

Правильное оформление текста запроса для универсальных отборов

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

Проанализируем пример использования расширения СКД:


ВЫБРАТЬ
    Справочник1.Ссылка КАК Ссылка
ИЗ
    Справочник.Справочник1 КАК Справочник1
{ГДЕ
    Справочник1.Ссылка.*}

Конструкция {ГДЕ ...} дает платформе явное указание, куда именно в SQL-запросе встраивать пользовательские отборы. Особенно это критично при работе с виртуальными таблицами регистров: там отбор обязательно должен пробрасываться внутрь параметров виртуальной таблицы через {ХАРАКТЕРИСТИКИ ...} или параметры таблицы, иначе система сначала вытянет весь регистр, а потом будет фильтровать его в памяти или на уровне временной таблицы.

Современные альтернативные подходы

Если ваша конфигурация написана на управляемых формах, ручное помещение настроек в ХранилищеЗначения является устаревшим подходом. Рассмотрим более эффективные механизмы:

  1. Системные хранилища настроек. Вместо ручной упаковки используйте ХранилищеСистемныхНастроек или ХранилищеНастроекДанныхФормы. Платформа 1С:Предприятие 8.3 умеет сохранять пользовательские настройки (в том числе отборы СКД) автоматически при закрытии формы и прозрачно восстанавливать их при открытии.
  2. Использование динамического списка. Если отбор данных вам нужен исключительно для визуального отображения на форме (например, для массовой обработки документов), нет нужды программно формировать таблицу значений. Используйте ДинамическийСписок. У него «под капотом» работает свой КомпоновщикНастроекПользовательский, который сам формирует отборы, применяет условное оформление и поддерживает сохранение пользовательских вариантов без написания сложного кода процессора вывода.

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

← На главную