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