При программном формировании отчетов на базе схемы компоновки данных (СКД) разработчики часто сталкиваются с исключениями при установке фильтров. Рассмотрим типичную ситуацию: при попытке добавить новый элемент отбора в коллекцию настроек компоновщик генерирует ошибку «Несоответствие типов» при заполнении вида сравнения, а на этапе генерации макета сообщает: «Ошибка в элементе отбора: глобальные элементы отбора обязательно должны использовать поля...».
Разберем по шагам, почему возникают эти исключения и как правильно настроить программный отбор в отчете.
Проанализируем строку кода, вызывающую первое исключение:
ЭлементОтбора.ВидСравнения = ВидСравнения.Равно;
В платформе 1С:Предприятие существуют два внешне похожих системных перечисления:
ВидСравнения — применяется для стандартных объектов платформы (например, в свойствах динамических списков, построителях отчетов или таблицах значений).ВидСравненияКомпоновкиДанных — специальное перечисление, разработанное исключительно для подсистемы компоновки данных.Коллекция ЭлементОтбораКомпоновкиДанных строго типизирована. Свойство ВидСравнения ожидает значение именно типа ВидСравненияКомпоновкиДанных. Передача стандартного ВидСравнения.Равно приводит к исключению времени выполнения с причиной «Несоответствие типов».
Для исправления достаточно явно указать нужное перечисление:
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
Вторая распространенная ошибка скрывается в формировании левой части условия. Посмотрим, как разработчик попытался связать отбор с полем схемы:
ПолеНоменклатура = Схема.НаборыДанных[0].Поля.Найти("Номенклатура");
ЭлементОтбора.ЛевоеЗначение = ПолеНоменклатура;
Метод Найти в коллекции полей набора данных возвращает объект типа ПолеНабораДанныхСхемыКомпоновкиДанных. Однако структура настроек компоновщика оперирует абстракцией полей, а не элементами описания схемы данных.
Когда вызывается метод КомпоновщикМакета.Выполнить, генератор макета проверяет глобальные отборы отчета. На этом уровне платформа требует, чтобы левым операндом выступало исключительно ПолеКомпоновкиДанных. Если в ЛевоеЗначение передана строка, объект поля набора данных, число или ссылка, генерируется системная ошибка: «глобальные элементы отбора обязательно должны использовать поля...».
Это ограничение связано с тем, что глобальный отбор транслируется платформой напрямую в результирующий SQL-запрос к базе данных. Платформе необходимо знать точный путь к данным поля компоновки. Чтобы исправить код, создадим новый экземпляр нужного типа:
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Номенклатура");
Соберем все исправления вместе и посмотрим на рабочий вариант функции вывода отчета с программным отбором:
Функция СформироватьОтчет() Экспорт
// 1. Получаем схему компоновки данных из макета
Схема = ПолучитьМакет("Макет");
// 2. Получаем настройки по умолчанию
Настройки = Схема.НастройкиПоУмолчанию;
// 3. Создаем и заполняем элемент отбора
ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Номенклатура");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Справочники.Номенклатура.НайтиПоНаименованию("Палка телескопическая (Чехия)");
ЭлементОтбора.Использование = Истина;
// 4. Формируем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакета.Выполнить(Схема, Настройки, Неопределено);
// 5. Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(Макет);
// 6. Выводим результат в табличный документ
ТабличныйДокумент = Новый ТабличныйДокумент;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Возврат ТабличныйДокумент;
КонецФункции
Обратим внимание: в примере мы также оптимизировали цикл вывода, заменив построчный обход метода Следующий() на единый вызов ПроцессорВывода.Вывести(ПроцессорКомпоновки), что существенно сокращает объем кода.
Рассмотрим несколько правил, которые помогут избежать ошибок при программной настройке отчетов:
ЭлементОтбора.Использование = Истина;. По умолчанию при программном создании элемент может не примениться, если флаг активности не взведен явно.
ПолеПроверки = Новый ПолеКомпоновкиДанных("Номенклатура");
Если Настройки.ДоступныеПоляОтбора.НайтиПоле(ПолеПроверки) <> Неопределено Тогда
// Создаем элемент отбора
КонецЕсли;
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Номенклатура", СсылкаНоменклатура);
ГДЕ исходного запроса, позволяя СУБД задействовать индексы таблиц сразу на этапе выборки строк.{ГДЕ Номенклатура.*}. Это гарантирует бесшовную трансляцию глобального отбора компоновщика в текст запроса к базе.