Как добавить фильтр по реквизиту табличной части в форму списка документов 1С

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача предоставить пользователю возможность фильтровать список документов не только по данным «шапки» (дата, номер, контрагент), но и по содержимому табличных частей. Типовой механизм отборов в управляемых формах отлично справляется с реквизитами самого объекта, но работа с табличными частями требует особого подхода из-за архитектурных особенностей хранения данных в реляционных базах данных. Давайте разберем, как правильно реализовать такой фильтр, обеспечив при этом высокую производительность системы.

Постановка задачи и выбор архитектурного решения

Представим ситуацию: в документе есть табличная часть, в которую добавлен строковый реквизит ОтправительДокумента. Нам необходимо вывести в форму списка поле ввода, при изменении которого список документов будет автоматически фильтроваться, оставляя только те документы, где в любой из строк табличной части встречается указанный отправитель. Проанализируем проблему: связь между документом и его табличной частью — это отношение «один ко многим». Если мы просто присоединим таблицу строк к основному запросу списка, мы получим дублирование строк документов (одна строка документа на каждую строку табличной части). Чтобы этого избежать, мы рассмотрим два основных метода реализации.

Шаг 1. Подготовка метаданных

Прежде чем приступать к программному коду, проверим настройки в Конфигураторе. Важно понимать различие между реквизитом формы и реквизитом объекта. Реквизит формы существует только пока открыто окно, а реквизит объекта (документа) сохраняется в базе данных. Для того чтобы фильтрация была возможна, ОтправительДокумента должен быть реквизитом именно табличной части документа в дереве конфигурации.

Для обеспечения приемлемой скорости поиска, особенно если база содержит тысячи документов, необходимо установить свойство Индексировать для нашего реквизита в табличной части. Это позволит СУБД быстро находить нужные строки без полного сканирования таблиц.

Шаг 2. Настройка динамического списка с произвольным запросом

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

  1. Откроем форму списка документа.
  2. Перейдем к свойствам реквизита Список.
  3. Установим флаг Произвольный запрос и нажмем Открыть в поле Настройка списка.

Нам необходимо модифицировать текст запроса так, чтобы он проверял наличие хотя бы одной строки в табличной части, соответствующей фильтру. Рассмотрим наиболее корректный с точки зрения производительности вариант с использованием конструкции ГДЕ Ссылка В (...) или ГДЕ ЕСТЬ NULL (через левое соединение с группировкой), но оптимальным будет использование вложенного запроса.

Проанализируем пример текста запроса:


ВЫБРАТЬ
    ДокументСписок.Ссылка КАК Ссылка,
    ДокументСписок.ПометкаУдаления КАК ПометкаУдаления,
    ДокументСписок.Номер КАК Номер,
    ДокументСписок.Дата КАК Дата,
    ДокументСписок.Проведен КАК Проведен
ИЗ
    Документ.ИмяВашегоДокумента КАК ДокументСписок
ГДЕ
    (&ОтправительПуст ИЛИ ДокументСписок.Ссылка В (
        ВЫБРАТЬ
            ТЧ.Ссылка
        ИЗ
            Документ.ИмяВашегоДокумента.ИмяТабличнойЧасти КАК ТЧ
        ГДЕ
            ТЧ.ОтправительДокумента ПОДОБНО &Отправитель
    ))

В данном запросе мы используем параметр &Отправитель для фильтрации и вспомогательный параметр &ОтправительПуст, чтобы не применять фильтр, когда поле поиска не заполнено.

Шаг 3. Создание интерфейса и программная обработка

Теперь добавим на форму поле, в которое пользователь будет вводить имя отправителя. Назовем его ФильтрОтправитель. Тип данных — Строка.

Для этого элемента управления нам нужно создать обработчик события ПриИзменении. В этом обработчике мы будем передавать значение из поля в параметры динамического списка. Разберем программный код:


&НаКлиенте
Процедура ФильтрОтправительПриИзменении(Элемент)
    
    УстановитьПараметрыСписка();
    
КонецПроцедуры

&НаСервере
Процедура УстановитьПараметрыСписка()
    
    // Определяем, заполнено ли поле фильтра
    ЗначениеЗаполнено = ЗначениеЗаполнено(ФильтрОтправитель);
    
    // Устанавливаем параметры в динамический список
    // Используем конструкцию ПОДОБНО, добавляя спецсимволы "%" для поиска по подстроке
    Список.Параметры.УстановитьЗначениеПараметра("Отправитель", "%" + ФильтрОтправитель + "%");
    Список.Параметры.УстановитьЗначениеПараметра("ОтправительПуст", НЕ ЗначениеЗаполнено);
    
КонецПроцедуры

Использование знаков процента в параметре &Отправитель позволяет реализовать гибкий поиск: если пользователь введет «Иванов», система найдет и «Иванов И.И.», и «Иванов и сыновья».

Шаг 4. Альтернативный метод — денормализация данных

Разберем ситуацию, когда поиск по табличной части начинает «тормозить» форму списка. Это происходит при огромном количестве строк в табличных частях. Опытные разработчики применяют метод дублирования данных в шапку. Выясним, в чем его суть:

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

Пример кода в модуле объекта:


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

В этом случае в форме списка нам не нужно менять запрос динамического списка. Мы сможем использовать стандартный механизм отборов 1С по реквизиту шапки СписокОтправителейДляПоиска. Это решение работает максимально быстро, так как СУБД ищет данные в одной таблице документов.

Заключение и рекомендации

Мы рассмотрели два основных пути решения задачи. Выбор метода зависит от ваших требований к производительности и сложности данных. Если данных немного — используйте произвольный запрос с вложенным ВЫБРАТЬ. Если система высоконагруженная и важна скорость открытия списка — лучше прибегнуть к дублированию данных в реквизит шапки при записи документа.

Посмотрим на важные моменты:

Таким образом, комбинируя визуальные средства платформы и небольшие вставки программного кода, можно создать удобный и быстрый интерфейс для конечного пользователя 1С.

← На главную