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