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