Как исправить ошибки при программном добавлении отбора в СКД?

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

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

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

Причина 1: Неверный тип перечисления для вида сравнения

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

ЭлементОтбора.ВидСравнения = ВидСравнения.Равно;

В платформе 1С:Предприятие существуют два внешне похожих системных перечисления:

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

Коллекция ЭлементОтбораКомпоновкиДанных строго типизирована. Свойство ВидСравнения ожидает значение именно типа ВидСравненияКомпоновкиДанных. Передача стандартного ВидСравнения.Равно приводит к исключению времени выполнения с причиной «Несоответствие типов».

Для исправления достаточно явно указать нужное перечисление:

ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;

Причина 2: Некорректный тип операнда в свойстве ЛевоеЗначение

Вторая распространенная ошибка скрывается в формировании левой части условия. Посмотрим, как разработчик попытался связать отбор с полем схемы:


ПолеНоменклатура = Схема.НаборыДанных[0].Поля.Найти("Номенклатура");
ЭлементОтбора.ЛевоеЗначение = ПолеНоменклатура;

Метод Найти в коллекции полей набора данных возвращает объект типа ПолеНабораДанныхСхемыКомпоновкиДанных. Однако структура настроек компоновщика оперирует абстракцией полей, а не элементами описания схемы данных.

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

Это ограничение связано с тем, что глобальный отбор транслируется платформой напрямую в результирующий SQL-запрос к базе данных. Платформе необходимо знать точный путь к данным поля компоновки. Чтобы исправить код, создадим новый экземпляр нужного типа:

ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Номенклатура");

Исправленный пример программного формирования отчета

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


Функция СформироватьОтчет() Экспорт 

	// 1. Получаем схему компоновки данных из макета
	Схема = ПолучитьМакет("Макет");	 

	// 2. Получаем настройки по умолчанию
	Настройки = Схема.НастройкиПоУмолчанию;	   
	
	// 3. Создаем и заполняем элемент отбора
	ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Номенклатура");
	ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
	ЭлементОтбора.ПравоеЗначение = Справочники.Номенклатура.НайтиПоНаименованию("Палка телескопическая (Чехия)");
	ЭлементОтбора.Использование = Истина;
	
	// 4. Формируем макет компоновки
	КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
	Макет = КомпоновщикМакета.Выполнить(Схема, Настройки, Неопределено);
	
	// 5. Инициализируем процессор компоновки
	ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
	ПроцессорКомпоновки.Инициализировать(Макет);
	
	// 6. Выводим результат в табличный документ
	ТабличныйДокумент = Новый ТабличныйДокумент;
	ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
	ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);
	
	ПроцессорВывода.Вывести(ПроцессорКомпоновки);
	
	Возврат ТабличныйДокумент;
	
КонецФункции

Обратим внимание: в примере мы также оптимизировали цикл вывода, заменив построчный обход метода Следующий() на единый вызов ПроцессорВывода.Вывести(ПроцессорКомпоновки), что существенно сокращает объем кода.

Полезные рекомендации по работе с отборами в СКД

Рассмотрим несколько правил, которые помогут избежать ошибок при программной настройке отчетов:

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