При разработке отчетов на базе Системы компоновки данных (СКД) часто возникает необходимость передать в параметры запроса не одно значение, а целый список (например, массив счетов или номенклатуры), сформированный программно. В этой статье мы подробно разберем, почему стандартные попытки передачи таблицы значений могут не работать, как правильно использовать методы компоновщика настроек и где лучше всего размещать код установки параметров для обеспечения стабильной работы отчета.
Рассмотрим ситуацию, с которой сталкиваются многие разработчики: в коде формы выполняется запрос, результат которого выгружается в таблицу значений, а затем эта таблица присваивается параметру СКД. Проанализируем исходный код, который часто приводит к ошибке:
&НаСервереБезКонтекста
Функция ПриОткрытииНаСервере()
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ ПланСчетов.Хозрасчетный ГДЕ Ссылка В ИЕРАРХИИ(&Родитель)";
Запрос.УстановитьПараметр("Родитель", ПланыСчетов.Хозрасчетный.РасчетыСПокупателямиИЗаказчиками);
Возврат Запрос.Выполнить().Выгрузить(); // Ошибка здесь: возвращается ТаблицаЗначений
КонецФункции
Основная проблема заключается в том, что параметр СКД, предназначенный для использования в условиях В ИЕРАРХИИ или В СПИСКЕ, ожидает объект типа Массив или СписокЗначений. Платформа 1С не может автоматически преобразовать ТаблицаЗначений в список элементов, даже если в таблице всего одна колонка. Чтобы исправить это, нам необходимо выгрузить конкретную колонку. Разберем правильный подход:
// Вместо Выгрузить() используем ВыгрузитьКолонку()
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
СчетаМассив = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");
Возврат СчетаМассив;
КонецЕсли;
Вместо ручного поиска элемента в коллекции ПараметрыДанных и установки свойства Значение, рекомендуется использовать встроенный метод УстановитьЗначениеПараметра. Проанализируем преимущества этого метода. Во-первых, он автоматически устанавливает флаг Использование в значение Истина. Во-вторых, он работает быстрее и читается проще. Посмотрим на пример кода:
// Вместо трех строк поиска и установки:
// Элемент = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("Счет");
// Элемент.Использование = Истина;
// Элемент.Значение = Счета;
// Используем одну эффективную строку:
Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Счет", Счета);
В современных конфигурациях на управляемых формах параметры отчета часто выносятся в область пользовательских настроек (шапка отчета). Выясним важный нюанс: если мы программно меняем параметр в КомпоновщикНастроек.Настройки, а этот параметр уже есть в КомпоновщикНастроек.ПользовательскиеНастройки, то визуально на форме значение может не измениться, так как пользовательские настройки имеют приоритет.
Для решения этой проблемы необходимо убедиться, что изменения отражены в обеих коллекциях. Метод УстановитьЗначениеПараметра в последних версиях платформы 8.3 умеет синхронизировать эти данные автоматически, если параметр корректно связан через ИдентификаторПользовательскойНастройки. Однако, если вы работаете со сложными структурами, полезно проверить наличие параметра в пользовательских настройках вручную:
Для Каждого ЭлементНастройки Из Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы Цикл
Если ТипЗнч(ЭлементНастройки) = Тип("ЗначениеПараметраКомпоновкиДанных")
И ЭлементНастройки.Параметр = Новый ПараметрКомпоновкиДанных("Счет") Тогда
ЭлементНастройки.Значение = Счета;
ЭлементНастройки.Использование = Истина;
КонецЕсли;
КонецЦикла;
Рассмотрим архитектурный совет: установка параметров в событии ПриОткрытии формы не всегда является лучшим решением. Если отчет будет формироваться программно (например, регламентным заданием или из другой обработки), код формы просто не выполнится. Проанализируем альтернативный вариант — использование модуля объекта отчета и процедуры ПриКомпоновкеРезультата.
Этот метод гарантирует выполнение кода непосредственно перед генерацией отчета, независимо от того, открыта форма или нет. Рассмотрим пример реализации в модуле объекта:
Процедура ПриКомпоновкеРезультата(ДанныеРасшифровки, СтандартнаяОбработка)
// Получаем значение параметра, если оно еще не установлено пользователем
ПараметрСчет = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("Счет");
Если ПараметрСчет <> Неопределено И Не ПараметрСчет.Использование Тогда
// Здесь мы можем вызвать серверную функцию для получения списка счетов
СписокСчетов = ПолучитьСписокСчетовПрограммно();
КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Счет", СписокСчетов);
КонецЕсли;
КонецПроцедуры
Когда мы работаем с планом счетов или регистрами бухгалтерии, крайне важно передавать параметры не просто в условия ГДЕ, а непосредственно в параметры виртуальных таблиц. Это существенно повышает производительность СУБД. Выясним, как это выглядит в тексте запроса СКД:
Неправильно (медленно):
ВЫБРАТЬ * ИЗ РегистрБухгалтерии.Хозрасчетный.Остатки КАК Остатки
ГДЕ Остатки.Счет В ИЕРАРХИИ (&Счет)
Правильно (быстро):
ВЫБРАТЬ * ИЗ РегистрБухгалтерии.Хозрасчетный.Остатки(, Счет В ИЕРАРХИИ (&Счет), , ) КАК Остатки
При таком подходе платформа накладывает фильтр на этапе формирования временных таблиц базы данных, что исключает обработку лишних записей.
Разберем еще один эффективный способ, который позволяет избежать написания лишнего кода в модулях. В СКД на закладке "Параметры" есть колонка "Выражение". Здесь можно использовать функции общих модулей или встроенного языка. Например, если вам всегда нужно получать иерархию определенного счета, вы можете прописать в поле выражения:
// В поле "Выражение" для параметра в СКД
ПланыСчетов.Хозрасчетный.РасчетыСПокупателямиИЗаказчиками
Если же требуется более сложная логика (например, получение массива), можно создать функцию в общем модуле с флагом Сервер и вызвать её прямо из выражения параметра СКД: МойОбщийМодуль.ПолучитьСписокСчетовДляОтчета().
Подведем итоги и составим алгоритм действий для надежной передачи параметров в СКД:
Массив или СписокЗначений, а не таблицу значений.КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Имя", Значение) для автоматической активации параметра.ПользовательскиеНастройки.ПриКомпоновкеРезультата) для универсальности.Следуя этим рекомендациям, вы сможете создавать гибкие и производительные отчеты, которые корректно обрабатывают динамически формируемые фильтры и списки значений.