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