При разработке интерфейсов на управляемых формах часто возникает задача вывести в динамический список данные, которые отсутствуют в базе в явном виде. Например, нам нужно собрать в одну строку названия всех товаров из табличной части документа или перечислить ответственных лиц. Самый простой путь, который выбирают многие разработчики, — использование обработчика ПриПолученииДанныхНаСервере. Мы программно обходим строки, производим вычисления и записываем результат в ОформлениеСтроки или непосредственно в данные строки.
Однако здесь мы сталкиваемся с критической проблемой: стандартный поиск перестает работать. Разберем ситуацию: динамический список выполняет запрос к базе данных (SQL), и поиск отрабатывает именно на уровне СУБД. Те данные, которые мы «дорисовали» программно в коде 1С, существуют только в памяти сервера приложений и только для текущей страницы списка. База данных о них ничего не знает, поэтому поиск по таким колонкам всегда будет выдавать пустой результат. Рассмотрим, как решить эту задачу правильно.
Проанализируем самый надежный и производительный метод — хранение заранее вычисленного значения. Если нам нужно искать по конкатенированной строке, эта строка должна физически существовать в таблице базы данных. Рассмотрим алгоритм реализации:
СтрокаДляПоиска с типом Строка (длину выберем исходя из задач, можно неограниченную).ПередЗаписью опишем логику сбора данных. Мы обходим табличную часть, соединяем значения и записываем результат в наш новый реквизит.Преимущества: Поиск работает мгновенно, так как выполняется стандартными средствами СУБД по индексированному (желательно) полю. Нагрузка на сервер при прокрутке списка минимальна.
Пример кода в модуле объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Собираем данные из табличной части "Товары"
ТекстДляПоиска = "";
Для Каждого СтрокаТЧ Из Товары Цикл
ТекстДляПоиска = ТекстДляПоиска + СтрокаТЧ.Номенклатура.Наименование + "; ";
КонецЦикла;
// Сохраняем в реквизит документа
СодержимоеТЧДляПоиска = ТекстДляПоиска;
КонецПроцедуры
Если версия платформы позволяет, мы можем попробовать использовать механизмы системы компоновки данных, на которой базируется динамический список. В настройках динамического списка можно добавить вычисляемое поле. Однако помните: если поле вычисляется через функции общего модуля, поиск по нему все равно может не работать в режиме «серверного» поиска. Но мы можем задействовать функцию СОЕДИНИТЬСТРОКИ (или JOINSTRINGS) в агрегатах СКД.
Выясним нюанс: напрямую в тексте запроса динамического списка агрегатные функции для строк недоступны. Но если мы выводим список через отчет или используем специфические настройки компоновки, мы можем настроить группировку, где в ресурсах будет указано:
СоединитьСтроки(Наименование, ", ")
Но будьте осторожны: для динамического списка этот метод часто требует отказа от основной таблицы, что негативно сказывается на производительности и возможности редактирования строк.
Иногда программисты пытаются «обмануть» отсутствие функции GROUP_CONCAT в 1С, создавая монструозные запросы. Рассмотрим пример из обсуждения, где конкатенация имитируется через последовательное соединение таблиц. Этот метод крайне сложен в поддержке, но он позволяет получить результат силами СУБД, а значит — сохранить поиск.
Проанализируем фрагмент такого запроса (упрощенно):
ВЫБРАТЬ
Док.Ссылка КАК Ссылка,
МАКСИМУМ(ЕСТЬNULL(Т1.Номенклатура.Наименование, "")) + ", " +
МАКСИМУМ(ЕСТЬNULL(Т2.Номенклатура.Наименование, "")) КАК Конкатенация
ИЗ
Документ.РеализацияТоваровУслуг КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК Т1
ПО Т1.Ссылка = Док.Ссылка И Т1.НомерСтроки = 1
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК Т2
ПО Т2.Ссылка = Док.Ссылка И Т2.НомерСтроки = 2
СГРУППИРОВАТЬ ПО
Док.Ссылка
Важно: Как мы видим, такой подход требует заранее знать максимальное количество строк в ТЧ или ограничиваться разумным пределом. Для реальных задач этот метод считается «экзотическим» и не рекомендуется для высоконагруженных систем, так как количество соединений (JOIN) будет колоссальным.
Для опытных администраторов и разработчиков в клиент-серверном варианте существует вариант с созданием View (представления) на уровне SQL-сервера. В SQL-представлении можно использовать нативные функции СУБД, такие как STRING_AGG для MSSQL. После создания View, она подключается в 1С как Внешний источник данных. Динамический список, построенный на такой таблице, будет поддерживать поиск «из коробки», так как для 1С это будет обычное текстовое поле в базе данных.
Рассмотрим критерии выбора решения:
ПриПолученииДанныхНаСервере, но оно же и самое бесполезное для поиска.Подведем итог: Если ваша задача — обеспечить полноценный, быстрый и удобный поиск по объединенным данным в списке, откажитесь от идеи динамического формирования строк в момент отображения. Используйте избыточность данных. Запись одной подготовленной строки в реквизит при сохранении документа сэкономит ресурсы сервера и нервы пользователей, которым не придется искать данные вручную.