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