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