При разработке отчетов на системе компоновки данных (СКД) разработчики часто сталкиваются с задачей: дать пользователю возможность отобрать данные либо по конкретному элементу справочника (например, по одному контрагенту), либо по целой папке (группе контрагентов со всеми вложенными элементами). При этом важно сделать интерфейс простым, чтобы конечному пользователю не приходилось самостоятельно заходить в расширенные настройки и вручную переключать вид сравнения с Равно на В группе.
В процессе реализации этой задачи нередко возникает системное предупреждение: «Выберите элемент, а не группу! Для раскрытия групп используйте...», либо отчет возвращает пустой результат при выборе папки. Разберем по шагам, почему возникает эта ошибка, как работает механизм иерархии в платформе 1С:Предприятие и какими способами можно реализовать удобный отбор.
Для начала проанализируем поведение условия иерархического отбора. В схеме компоновки данных вид сравнения «В группе» полностью соответствует оператору языка запросов В ИЕРАРХИИ. Данный оператор обладает важным универсальным свойством:
Равно, возвращая только этот конкретный элемент.Таким образом, само по себе условие В группе закрывает обе потребности без изменения типа сравнения. Возникает вопрос: почему же пользователь получает ошибку при попытке выбрать группу в поле отбора?
Данная ошибка вызвана не ограничениями механизма СКД, а поведением элементов формы пользовательского интерфейса. В платформе «1С:Предприятие» у каждого ссылочного поля ввода и у параметров выбора существует свойство ВыборГруппИЭлементов. По умолчанию для полей справочников оно часто принимает значение Элементы или рассчитывается автоматически (Авто), разрешая выбирать только конечные элементы (не папки). При попытке подтвердить выбор группы форма блокирует действие и выдает сообщение об ошибке.
Рассмотрим подробнее проверенные способы решения этой задачи.
Если в вашем отчете используется собственная форма, настроить поведение поля выбора проще всего на уровне интерфейса формы:
ВыборГруппИЭлементов).После этого поле ввода позволит пользователю выбирать как отдельные позиции справочника, так и целые папки. В сочетании с видом сравнения отбора В группе система корректно отработает в обоих случаях.
Если отчет не имеет собственной формы и генерируется автоматически, оптимально использовать синтаксис расширения языка запросов компоновки данных. Это позволяет СКД динамически и корректно инициализировать доступные виды сравнения.
Посмотрим на пример оформления условия в тексте запроса набора данных:
ВЫБРАТЬ
ПродажиОбороты.Контрагент КАК Контрагент,
ПродажиОбороты.СуммаОборот КАК СуммаОборот
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты
{ГДЕ
ПродажиОбороты.Контрагент.* КАК Контрагент}
Конструкция {ГДЕ Поле.*} указывает СКД, что для поля Контрагент доступны все стандартные операции фильтрации, включая иерархические. В настройках отчета (на вкладке «Настройки» схемы компоновки) разработчик задает отбор по полю Контрагент с видом сравнения В группе и выносит его в «Быстрый доступ» (пользовательские настройки). Платформа применит режим выбора, разрешающий указывать и группы, и элементы.
Если фильтрация реализована не через стандартные отборы СКД, а через параметр данных запроса вида Контрагент В ИЕРАРХИИ (&Контрагент), настроим доступность групп на вкладке параметров схемы:
Контрагент.ВыборГруппИЭлементов и зададим ему значение Группы и элементы (объект ИспользованиеГруппИЭлементов.ГруппыИЭлементы).Иногда требуется оставить вид сравнения Равно для обычных позиций ради оптимизации запросов к СУБД, но переключать его на В группе, если выбрана папка. Разберем, как автоматизировать этот процесс в событии ПриКомпоновкеРезультата модуля отчета:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Получаем текущие настройки компоновщика
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Ищем отбор по нужному полю среди элементов отбора
Для Каждого ЭлементОтбора Из Настройки.Отбор.Элементы Цикл
Если ТипЗнч(ЭлементОтбора) = Тип("ЭлементОтбораКомпоновкиДанных")
И ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент")
И ЭлементОтбора.Использование Тогда
Если ЗначениеЗаполнено(ЭлементОтбора.ПравоеЗначение) Тогда
// Проверяем, является ли выбранный контрагент группой
Если ЭлементОтбора.ПравоеЗначение.ЭтоГруппа Тогда
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВИерархии;
Иначе
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Загружаем скорректированные настройки обратно
КомпоновщикНастроек.ЗагрузитьНастройки(Настройки);
КонецПроцедуры
Такой подход избавляет пользователя от необходимости следить за техническими деталями видов сравнения: он просто выбирает нужного контрагента или папку, а программа сама выставляет требуемый вид фильтрации перед формированием отчета.
Обратим внимание на особенности работы с условием В ИЕРАРХИИ на уровне СУБД:
В ИЕРАРХИИ (&Параметр) без проверки. Если параметр пуст, платформа попытается выполнить поиск принадлежности ко всему дереву таблицы, что вызовет полное сканирование (Table Scan) и критическое падение производительности. Условие всегда должно быть опциональным (заключенным в фигурные скобки {} СКД).В ИЕРАРХИИ создает временную таблицу с иерархическим деревом узлов. Прямое сравнение Равно по конечному элементу выполняется по индексу быстрее. Если в отчете предполагается частая выборка именно единичных элементов, программная подмена вида сравнения (Способ 4) снизит нагрузку на сервер баз данных.