При разработке в среде 1С:Предприятие 8 часто возникает задача открытия формы списка регистра сведений с установленным отбором. Простая фильтрация по прямому значению измерения (например, по конкретному договору или физическому лицу) не вызывает сложностей. Однако ситуация меняется, когда нам необходимо наложить отбор по свойству измерения — например, по владельцу справочника, который выступает в качестве измерения.
В этой статье мы подробно разберем, почему стандартный метод передачи структуры параметров вызывает ошибку «Недопустимое значение параметра», рассмотрим классический (но устаревший) способ решения этой задачи, а затем изучим современные и наиболее эффективные стандарты разработки 1С, включая вопросы оптимизации запросов к СУБД.
Представим структуру метаданных. У нас есть регистр сведений эпЗаказчикиПоАктуОбОказанииУслугПоПередачеЭлектроэнергии. Одним из его ключевых измерений является Заказчик (тип ссылки на справочник Заказчики). У этого справочника есть владелец — контрагент (тип ссылки на справочник Контрагенты).
Нам требуется открыть форму списка этого регистра из карточки контрагента (или из команды, связанной с контрагентом), автоматически отфильтровав записи так, чтобы отображались только те заказчики, которые принадлежат данному контрагенту.
Попытка передать отбор «в лоб» через простую структуру параметров формы вернет ошибку:
ЗначениеОтбора = Новый Структура("Заказчик.Владелец", ПараметрКоманды);
ПараметрыФормы = Новый Структура("Отбор", ЗначениеОтбора);
ОткрытьФорму("РегистрСведений...ФормаСписка", ПараметрыФормы);
Платформа выдает ошибку, так как в ключе структуры отбора Отбор нельзя использовать путь к данным через точку. Ключом структуры может быть только непосредственное имя измерения, ресурса или реквизита регистра.
Этот способ часто встречается на форумах и в старых конфигурациях. Суть его заключается в том, что мы сначала получаем программный объект формы списка, затем напрямую обращаемся к настройкам компоновки данных её основного динамического списка и добавляем туда новый элемент отбора.
Рассмотрим по шагам программный код, реализующий этот подход:
// 1. Получаем форму списка регистра программно
Форма = ПолучитьФорму(
"РегистрСведений.эпЗаказчикиПоАктуОбОказанииУслугПоПередачеЭлектроэнергии.ФормаСписка",
,
ПараметрыВыполненияКоманды.Источник,
ПараметрыВыполненияКоманды.Уникальность,
ПараметрыВыполненияКоманды.Окно,
ПараметрыВыполненияКоманды.НавигационнаяСсылка
);
// 2. Добавляем новый элемент отбора в коллекцию динамического списка
ЭлементОтбора = Форма.Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
// 3. Задаем левое значение (путь к полю через точку)
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Заказчик.Владелец");
// 4. Определяем вид сравнения и правое значение (наш Контрагент)
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = ПараметрКоманды; // Здесь передается ссылка на контрагента
ЭлементОтбора.Использование = Истина;
// 5. Открываем настроенную форму
Форма.Открыть();
Этот код успешно решает задачу. Но у него есть существенные недостатки с точки зрения современных стандартов разработки 1С. Использование метода ПолучитьФорму() с последующей модификацией её свойств на клиенте считается устаревшей практикой (legacy-кодом). Такой подход ухудшает клиент-серверное взаимодействие и может вызывать избыточные серверные вызовы при работе в Web-клиенте.
По стандартам разработки фирмы «1С» форму следует открывать напрямую через единый метод ОткрытьФорму(), передавая все настройки в специальном параметре — ФиксированныеНастройки. В него передается предварительно сконфигурированный объект НастройкиКомпоновкиДанных.
Проанализируем этот чистый и производительный вариант реализации:
// 1. Создаем пустой объект настроек компоновки данных
НастройкиКомпоновки = Новый НастройкиКомпоновкиДанных;
// 2. Добавляем элемент отбора компоновки данных
ЭлементОтбора = НастройкиКомпоновки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Заказчик.Владелец");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = ПараметрКоманды;
ЭлементОтбора.Использование = Истина;
// 3. Упаковываем настройки в структуру параметров открываемой формы
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ФиксированныеНастройки", НастройкиКомпоновки);
// 4. Открываем форму стандартным платформенным методом
ОткрытьФорму(
"РегистрСведений.эпЗаказчикиПоАктуОбОказанииУслугПоПередачеЭлектроэнергии.ФормаСписка",
ПараметрыФормы,
ПараметрыВыполненияКоманды.Источник,
ПараметрыВыполненияКоманды.Уникальность,
ПараметрыВыполненияКоманды.Окно,
ПараметрыВыполненияКоманды.НавигационнаяСсылка
);
Этот метод полностью соответствует стандартам разработки, корректно отрабатывает на любых типах клиентов (включая мобильный и веб-клиент) и не требует предварительной инициализации контекста формы на клиенте до её открытия.
Применяя отборы по реквизитам измерений (через точку, например Заказчик.Владелец), разработчик должен четко понимать последствия этого шага для производительности базы данных, особенно если регистр сведений содержит сотни тысяч или миллионы записей.
Выясним, что происходит на уровне СУБД:
Заказчик.Владелец = &Параметр, платформа 1С транслирует этот код в SQL-запрос с оператором LEFT JOIN (левое соединение) таблицы регистра сведений с таблицей справочника Заказчики.Заказчик. Вместо мгновенного поиска по индексу СУБД будет вынуждена выполнить сканирование всей таблицы (Table Scan или Index Scan), сопоставляя каждую строчку с таблицей справочника заказчиков.Решение проблемы производительности: Если данный отбор является критически важным и форма списка будет открываться пользователями постоянно, рекомендуется провести денормализацию данных. Добавьте в сам регистр сведений дополнительное измерение Контрагент (Владелец заказчика). При записи данных в регистр автоматически заполняйте это поле. В таком случае отбор будет производиться напрямую по индексированному измерению регистра без каких-либо левых соединений, что гарантирует мгновенный отклик системы.
При проектировании интерфейса важно различать поведение системы при наложении разных типов настроек:
Если вам требуется сделать отбор «мягким» (доступным для изменения пользователю), программно добавляйте его в свойство динамического списка КомпоновщикНастроек.ПользовательскиеНастройки внутри обработчика события формы ПриСозданииНаСервере.
Если ваша конфигурация построена на базе БСП, вы можете существенно сократить объем кода и сделать его более читаемым. Для этого используйте готовые методы общих модулей общего назначения.
Рассмотрим пример установки отбора с помощью БСП в коде формы списка:
// Пример установки отбора в обработчике ПриСозданииНаСервере формы списка
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
Список, // Наш динамический список
"Заказчик.Владелец", // Путь к полю
Параметры.КонтрагентСсылка, // Значение отбора
ВидСравненияКомпоновкиДанных.Равно,
"Отбор по владельцу заказчика", // Представление отбора для пользователя
Истина // Использование
);
Использование БСП избавляет разработчика от необходимости вручную создавать объекты типов компоновки данных и снижает вероятность совершения синтаксических ошибок в коде.