Как обеспечить поиск в динамическом списке 1С, если значения колонок формируются программно?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Решение №1: Денормализация и хранение данных в реквизите

Проанализируем самый надежный и производительный метод — хранение заранее вычисленного значения. Если нам нужно искать по конкатенированной строке, эта строка должна физически существовать в таблице базы данных. Рассмотрим алгоритм реализации:

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

Преимущества: Поиск работает мгновенно, так как выполняется стандартными средствами СУБД по индексированному (желательно) полю. Нагрузка на сервер при прокрутке списка минимальна.

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


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

Решение №2: Использование возможностей СКД в динамическом списке

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

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

СоединитьСтроки(Наименование, ", ")

Но будьте осторожны: для динамического списка этот метод часто требует отказа от основной таблицы, что негативно сказывается на производительности и возможности редактирования строк.

Решение №3: Реализация конкатенации на языке запросов

Иногда программисты пытаются «обмануть» отсутствие функции GROUP_CONCAT в 1С, создавая монструозные запросы. Рассмотрим пример из обсуждения, где конкатенация имитируется через последовательное соединение таблиц. Этот метод крайне сложен в поддержке, но он позволяет получить результат силами СУБД, а значит — сохранить поиск.

Проанализируем фрагмент такого запроса (упрощенно):


ВЫБРАТЬ
    Док.Ссылка КАК Ссылка,
    МАКСИМУМ(ЕСТЬNULL(Т1.Номенклатура.Наименование, "")) + ", " +
    МАКСИМУМ(ЕСТЬNULL(Т2.Номенклатура.Наименование, "")) КАК Конкатенация
ИЗ
    Документ.РеализацияТоваровУслуг КАК Док
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК Т1 
        ПО Т1.Ссылка = Док.Ссылка И Т1.НомерСтроки = 1
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК Т2 
        ПО Т2.Ссылка = Док.Ссылка И Т2.НомерСтроки = 2
СГРУППИРОВАТЬ ПО
    Док.Ссылка

Важно: Как мы видим, такой подход требует заранее знать максимальное количество строк в ТЧ или ограничиваться разумным пределом. Для реальных задач этот метод считается «экзотическим» и не рекомендуется для высоконагруженных систем, так как количество соединений (JOIN) будет колоссальным.

Решение №4: Использование внешних источников (SQL View)

Для опытных администраторов и разработчиков в клиент-серверном варианте существует вариант с созданием View (представления) на уровне SQL-сервера. В SQL-представлении можно использовать нативные функции СУБД, такие как STRING_AGG для MSSQL. После создания View, она подключается в 1С как Внешний источник данных. Динамический список, построенный на такой таблице, будет поддерживать поиск «из коробки», так как для 1С это будет обычное текстовое поле в базе данных.

Сравнительный анализ методов

Рассмотрим критерии выбора решения:

Подведем итог: Если ваша задача — обеспечить полноценный, быстрый и удобный поиск по объединенным данным в списке, откажитесь от идеи динамического формирования строк в момент отображения. Используйте избыточность данных. Запись одной подготовленной строки в реквизит при сохранении документа сэкономит ресурсы сервера и нервы пользователей, которым не придется искать данные вручную.

← На главную