При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с задачей вывода дополнительных данных в списки документов или справочников. Типичный пример: вывести список ответственных менеджеров из табличной части или текущий этап согласования из внешнего регистра сведений в одну строку через запятую. Однако, реализовав это через популярное событие ПриПолученииДанных, разработчик обнаруживает, что стандартные механизмы поиска (Ctrl+F) и отборы по этой колонке перестают работать. Разберем подробно, почему так происходит и как правильно решить эту задачу.
Для начала проанализируем внутренние механизмы платформы. Динамический список — это объект, который генерирует SQL-запрос к базе данных. Когда мы накладываем отбор или используем строку поиска, платформа добавляет в этот запрос конструкцию WHERE. База данных ищет только по тем полям, которые физически существуют в таблицах SQL или могут быть получены через соединения.
Событие ПриПолученииДанных срабатывает на стороне сервера 1С после того, как основной запрос к базе данных уже выполнен и данные для текущей страницы (обычно 30–45 строк) получены. Мы программно "дорисовываем" значения в ячейки для отображения пользователю. Платформа ничего не знает об этих значениях в контексте всей базы данных. Именно поэтому попытка найти документ по тексту, добавленному в этом событии, всегда будет возвращать пустой результат: в базе данных этого текста просто нет.
Рассмотрим наиболее производительный и надежный метод, который часто применяется в крупных конфигурациях, таких как 1С:ERP 2.5 или 1С:Комплексная автоматизация. Если нам нужно искать по строке, объединяющей данные из табличной части (например, список менеджеров), лучше всего хранить эту строку в реальном реквизите шапки документа.
Алгоритм реализации:
СписокМенеджеровСтрокой (Тип: Строка, Длина: Неограничена или 500+).ПередЗаписью реализуем формирование этой строки.Пример кода в модуле документа:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Формируем строку менеджеров на основании ТЧ "Товары"
ТаблицаМенеджеров = Товары.ВыгрузитьКолонку("Менеджер");
МассивУникальных = Новый Массив;
Для Каждого Менеджер Из ТаблицаМенеджеров Цикл
Если ЗначениеЗаполнено(Менеджер) И МассивУникальных.Найти(Менеджер) = Неопределено Тогда
МассивУникальных.Добавить(Строка(Менеджер));
КонецЕсли;
КонецЦикла;
СписокМенеджеровСтрокой = СтрСоединить(МассивУникальных, ", ");
КонецПроцедуры
Преимущества: Поиск и отбор работают мгновенно, так как используется индексированное (если нужно) поле таблицы. Нагрузка на сервер при открытии списка минимальна.
Если задача заключается в фильтрации по конкретному значению (например, найти все документы, где есть "Менеджер Иванов"), а не просто поиск по произвольной строке, мы можем изменить сам запрос динамического списка. Разберем, как подключить данные из подчиненных таблиц без дублирования строк в списке.
В тексте запроса динамического списка (на закладке "Запрос") можно использовать левое соединение с группировкой или вложенный запрос. Чтобы избежать появления нескольких строк для одного документа, используем конструкцию ГДЕ Ссылка В (...) в пользовательских настройках или параметрах запроса.
Если же мы хотим видеть список этапов согласования из Регистра Сведений, проанализируем следующий пример запроса:
ВЫБРАТЬ
ДокументПТУ.Ссылка,
ДокументПТУ.Дата,
ДокументПТУ.Номер,
ЕСТЬNULL(ВложенныйЗапрос.ЭтапыСогласования, "Не начато") КАК Этапы
ИЗ
Документ.ПриобретениеТоваровУслуг КАК ДокументПТУ
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
ОбъектСсылка КАК ОбъектСсылка,
МАКСИМУМ(Этап) КАК ЭтапыСогласования
ИЗ
РегистрСведений.ЭтапыСогласованияДокументов
СГРУППИРОВАТЬ ПО
ОбъектСсылка
) КАК ВложенныйЗапрос ПО ДокументПТУ.Ссылка = ВложенныйЗапрос.ОбъектСсылка
Важный нюанс: Язык запросов 1С не поддерживает агрегатную функцию STRING_AGG (объединение строк в одну). Поэтому вывести именно "список через запятую" прямо в запросе крайне сложно. В таких случаях лучше использовать Решение 1 или Решение 3.
Проанализируем ситуацию, когда нам не хочется менять структуру метаданных (добавлять реквизиты). Мы можем создать на форме списка свое поле ввода для поиска и при его изменении динамически модифицировать текст запроса списка.
Пошаговый алгоритм:
ОтборПоМенеджеру (тип СправочникСсылка.Пользователи или Строка).ПриИзменении этого реквизита напишем код, который добавит условие в КомпоновщикНастроек или изменит ТекстЗапроса.
&НаСервере
Процедура ОтборПоМенеджеруПриИзмененииНаСервере()
ТекстУсловия = "ГДЕ Ссылка В (ВЫБРАТЬ Ссылка ИЗ Документ.ПриобретениеТоваровУслуг.Товары ГДЕ Менеджер = &ВыбранныйМенеджер)";
// Получаем текущий текст запроса
ТекущийТекст = Список.ТекстЗапроса;
// Модифицируем его, добавляя условие (требуется аккуратная работа со строками)
// Или используем стандартный КомпоновщикНастроек для добавления элемента отбора
ЭлементОтбора = Список.КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
// Вычисляем массив ссылок заранее запросом
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Документ.ПриобретениеТоваровУслуг.Товары ГДЕ Менеджер = &М");
Запрос.УстановитьПараметр("М", ОтборПоМенеджеру);
ЭлементОтбора.ПравоеЗначение = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
ЭлементОтбора.Использование = ЗначениеЗаполнено(ОтборПоМенеджеру);
КонецПроцедуры
Малоизвестный, но эффективный метод. Если в свойствах документа включено Использовать полнотекстовый поиск, и реквизит табличной части также включен в индекс, то стандартное поле поиска в заголовке формы (которое ищет "везде") будет находить документ по имени менеджера, даже если его нет в колонках списка. Платформа сама найдет ссылку на документ через индексы табличных частей. Это не поможет сделать строгий отбор "по колонке", но решит задачу "быстро найти документ по менеджеру".
Рассмотрев все варианты, мы приходим к следующим выводам:
ПриПолученииДанных — это инструмент только для визуального оформления (цвета, картинки, иконки). Никогда не используйте его для данных, по которым требуется поиск.Выяснив причину проблемы, мы понимаем: чтобы отбор заработал, данные должны попасть в Запрос динамического списка либо как физическое поле таблицы, либо как результат соединения таблиц. Выбирайте метод денормализации, если вам важна простота поддержки и скорость работы пользователя.