Как правильно заполнить правое значение в отборе СКД списком значений?

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

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

Проанализируем причины такого поведения платформы 1С:Предприятие, разберем типовые ошибки и по шагам реализуем корректные варианты заполнения отбора.

Почему возникает ошибка при заполнении отбора

Выясним причину, по которой код ЭлементОтбора.ПравоеЗначение.ЗагрузитьЗначения(...) завершается аварийно. Для этого обратим внимание на два ключевых момента:

  1. Тип по умолчанию: При создании нового элемента отбора (объекта типа ЭлементОтбораКомпоновкиДанных) его свойство ПравоеЗначение всегда инициализируется значением Неопределено. В отличие от пользовательского интерфейса, где выбор вида сравнения ВСписке автоматически подставляет пустой список, в программном коде автоинициализации не происходит. Попытка вызвать метод у значения Неопределено приводит к исключению: попытка вызвать метод не существующего объекта.
  2. Сигнатура метода ЗагрузитьЗначения(): Метод ЗагрузитьЗначения() у объекта СписокЗначений является процедурой, а не функцией. Он ничего не возвращает. Если написать конструкцию вида ЭлементОтбора.ПравоеЗначение = Список.ЗагрузитьЗначения(Массив), свойству снова будет присвоено значение Неопределено.

Способ 1. Инициализация списка с последующей загрузкой массива

Разберем классическое исправление ошибки автора темы. Сначала явно создадим экземпляр объекта СписокЗначений, наполним его через метод ЗагрузитьЗначения(), и только после этого присвоим готовый список свойству ПравоеЗначение.

Посмотрим на рабочий пример кода:


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

МассНом = Новый Массив;
Для Каждого Эл Из ОтбНоменклатура Цикл
    Если Эл.Пометка Тогда
        МассНом.Добавить(Эл.Значение);
    КонецЕсли;    
КонецЦикла;

// Создаем пустой список значений
СписокСравнения = Новый СписокЗначений;
// Заполняем его из сформированного массива
СписокСравнения.ЗагрузитьЗначения(МассНом);

// Присваиваем заполненную коллекцию в отбор
ЭлементОтбора1.ПравоеЗначение = СписокСравнения;
ЭлементОтбора1.Использование  = (СписокСравнения.Количество() > 0);

Способ 2. Прямое заполнение списка без промежуточного массива

Проанализируем предыдущий вариант с точки зрения оптимальности. Создание промежуточного объекта Массив с последующим вызовом ЗагрузитьЗначения() создает лишнюю нагрузку на память и процессор, особенно если количество обрабатываемых строк велико. Гораздо эффективнее сразу добавлять выбранные элементы непосредственно в СписокЗначений.

Рассмотрим реализацию без лишних промежуточных структур:


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

// Инициализируем список сразу
СписокНоменклатуры = Новый СписокЗначений;
Для Каждого Эл Из ОтбНоменклатура Цикл
    Если Эл.Пометка Тогда
        СписокНоменклатуры.Добавить(Эл.Значение);
    КонецЕсли;    
КонецЦикла;

// Устанавливаем правое значение
ЭлементОтбора1.ПравоеЗначение = СписокНоменклатуры;
// Включаем использование отбора только при наличии выбранных позиций
ЭлементОтбора1.Использование  = (СписокНоменклатуры.Количество() > 0);

Способ 3. Использование функций БСП

Если конфигурация разработана с использованием Библиотеки стандартных подсистем (БСП), для управления условиями компоновки рекомендуется применять готовую типовую процедуру ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(). Она автоматически обрабатывает проверку типов, корректно устанавливает вид сравнения и управляет активностью флага использования.

Посмотрим на пример установки отбора через БСП:


СписокНоменклатуры = Новый СписокЗначений;
Для Каждого Эл Из ОтбНоменклатура Цикл
    Если Эл.Пометка Тогда
        СписокНоменклатуры.Добавить(Эл.Значение);
    КонецЕсли;    
КонецЦикла;

Использование = (СписокНоменклатуры.Количество() > 0);

ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(
    КомпоновщикНастроек.Настройки.Отбор,
    "Номенклатура",
    СписокНоменклатуры,
    ВидСравненияКомпоновкиДанных.ВСпискеПоИерархии,
    ,
    Использование
);

Важные нюансы и подводные камни при работе с отборами СКД

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

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