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

Программист 1С v8.3 (Обычные формы)
← На главную

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

Анализ проблемы: почему возникает ошибка «Недопустимый тип сравнения»

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

Проанализируем основные причины такого поведения:

  1. Ограничение метода Установить(): Как справедливо отмечено в сообщениях форума, метод Установить() у элемента отбора не просто передает значение, но и принудительно устанавливает вид сравнения в Равно. Если в качестве значения передается СписокЗначений, платформа пытается найти документ, у которого реквизит буквально равен всему списку целиком, что невозможно.
  2. Архитектура критериев отбора: В обычных формах (реквизит типа ДокументСписок) критерии отбора работают как жестко заданные индексы. Технически платформа 1С оптимизирует работу с ними только для вида сравнения Равно. Вид сравнения ВСписке для критериев отбора зачастую просто не поддерживается на уровне ядра платформы в данном контексте, что и вызывает исключение «Недопустимый тип сравнения».
  3. Особенности визуализации: Даже если программно удается избежать ошибки, критерий отбора в списке может не поддерживать множественный выбор через стандартный интерфейс.

Решение №1: Использование стандартного критерия отбора (ограниченный вариант)

Если нам достаточно отбора только по одному значению, мы можем использовать стандартный механизм. Посмотрим, как правильно инициализировать такой отбор, избегая типичных ошибок со сбросом параметров. Вместо метода Установить(), который «зашивает» вид сравнения, мы можем обращаться к свойствам напрямую.


// Пример установки отбора по одному значению через критерий
СкладДляПоиска = Перечисления.Место.Склад1;
ОтборЭлемент = ДокументСписок.Отбор.ОтборПоМесто;

ОтборЭлемент.Использование = Истина;
ОтборЭлемент.ВидСравнения = ВидСравнения.Равно;
ОтборЭлемент.Значение = СкладДляПоиска;

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

Решение №2: Универсальный метод через запрос и отбор по ссылке

Поскольку механизм КритерийОтбора в обычных формах не позволяет использовать ВидСравнения.ВСписке, наиболее надежным и производительным решением будет предварительное получение списка подходящих документов с помощью запроса и последующая установка отбора по полю Ссылка. Поле Ссылка гарантированно поддерживает вид сравнения ВСписке.

Разберем этот алгоритм по шагам:

  1. Сформируем список значений, по которым нужно фильтровать документы.
  2. Выполним запрос к табличной части документа, выбрав уникальные ссылки на документы, где реквизит соответствует нашему списку.
  3. Выгрузим результат запроса в массив или список значений.
  4. Установим отбор в объекте ДокументСписок по полю Ссылка.

Проанализируем пример кода, реализующий этот подход:


Процедура УстановитьОтборПоСкладам()
    
    // 1. Подготовка списка искомых значений
    СписокМест = Новый СписокЗначений;
    СписокМест.Добавить(Перечисления.Место.Склад);
    СписокМест.Добавить(Перечисления.Место.Склад2);
    СписокМест.Добавить(Перечисления.Место.Склад3);
    
    // 2. Запрос для поиска документов
    // Используем РАЗЛИЧНЫЕ, чтобы не было дублей ссылок
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |   ЗаказПоставщикуТовары.Ссылка КАК Ссылка
        |ИЗ
        |   Документ.ЗаказПоставщику.Товары КАК ЗаказПоставщикуТовары
        |ГДЕ
        |   ЗаказПоставщикуТовары.Место В (&СписокМест)";
    
    Запрос.УстановитьПараметр("СписокМест", СписокМест);
    
    РезультатЗапроса = Запрос.Выполнить();
    
    // 3. Получение массива ссылок
    МассивСсылок = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");
    
    // 4. Установка отбора в списке
    // Поле "Ссылка" всегда доступно для отбора "В списке"
    ДокументСписок.Отбор.Ссылка.ВидСравнения = ВидСравнения.ВСписке;
    ДокументСписок.Отбор.Ссылка.Значение.ЗагрузитьЗначения(МассивСсылок);
    ДокументСписок.Отбор.Ссылка.Использование = Истина;

КонецПроцедуры

Важный нюанс: Если результат запроса пустой (документы не найдены), установка пустого списка в отбор приведет к тому, что список документов станет пустым. Это корректное поведение. Если же вы хотите при пустом фильтре показывать все документы, добавьте проверку МассивСсылок.Количество() > 0.

Сравнение подходов: Критерии vs Ссылки

Выясним причину, почему разработчики часто пытаются использовать именно критерии отбора. Критерий — это индекс. В теории он должен работать быстрее. Однако в 1С обычные формы имеют свои внутренние механизмы работы с базой данных. Когда мы устанавливаем отбор по Ссылке и передаем туда массив, платформа генерирует эффективный SQL-запрос с условием WHERE ID IN (...).

Если таблица документов огромная (миллионы записей), а подходящих документов мало, отбор по ссылке отработает мгновенно. Если же подходящих документов очень много (например, 100 000), такой отбор может замедлить работу формы. В этом случае стоит задуматься об ограничении периода или других дополнительных фильтрах.

Особенности работы в управляемых формах

Хотя обсуждаемая тема касается обычных форм, кратко рассмотрим, как эта же задача решается в современных управляемых формах. В них основным инструментом является ДинамическийСписок.

В динамическом списке нам вообще не нужны критерии отбора для таких задач. Мы можем изменить текст запроса динамического списка, добавив соединение с табличной частью или условие ГДЕ. Это гораздо гибче, так как позволяет использовать ВидСравнения.ВСписке напрямую в настройках компоновки данных (СКД), которые лежат в основе динамического списка.

Резюме

Подведем итоги нашего анализа:

Соблюдение этих рекомендаций позволит вам создавать быстрые и удобные интерфейсы для пользователей, обходя архитектурные ограничения старых версий платформы.

← На главную