При проектировании систем на платформе 1С:Предприятие часто возникает необходимость создания универсальных регистров сведений для хранения дополнительных реквизитов, комментариев или файлов, привязанных к различным типам документов. В качестве ключевого разреза в таких регистрах обычно выступает измерение с составным типом данных, содержащим ссылки на различные документы конфигурации. Рано или поздно разработчик сталкивается с задачей: как открыть форму списка этого универсального регистра из формы списка конкретного документа и отобразить записи исключительно по этому виду документа.
В этой статье мы подробно разберем несколько эффективных практических способов реализации такого отбора, проанализируем их влияние на производительность СУБД и выберем оптимальный вариант для вашей конфигурации.
Представим, что в расширении создан вспомогательный регистр сведений СводныйРегистрДополнительныйКомментарий. У него есть ключевое измерение ДокументКомментарий (составной тип, включающий три вида документов) и ресурс Комментарий (строка). Нам требуется реализовать кнопку в форме списка документов (например, Реализация товаров и услуг), при нажатии на которую открывается форма списка регистра сведений, где отображаются комментарии только к документам реализации. При этом отбор должен накладываться динамически, без жесткого кодирования под один тип данных, чтобы форму списка регистра можно было универсально использовать для всех трех видов документов.
---
Это наиболее декларативный и гибкий метод, который не требует изменения структуры метаданных и динамической склейки текста запроса в коде. Суть метода заключается в добавлении вычисляемого поля типа непосредственно в статический запрос динамического списка формы регистра.
Выполним настройку по шагам:
Список.ТИПЗНАЧЕНИЯ:
ВЫБРАТЬ
Рег.Период,
Рег.ДокументКомментарий,
Рег.Комментарий,
ТИПЗНАЧЕНИЯ(Рег.ДокументКомментарий) КАК ТипДокумента
ИЗ
РегистрСведений.СводныйРегистрДополнительныйКомментарий КАК Рег
Теперь подготовим код вызова формы списка регистра из формы списка нашего документа. При нажатии кнопки мы программно определяем тип текущего документа и передаем его в параметрах формы:
&НаКлиенте
Процедура ПросмотрКомментариев(Команда)
ПараметрыФормы = Новый Структура;
// Передаем системный тип документа, список которого сейчас открыт
ПараметрыФормы.Вставить("ФильтрПоТипуДокумента", Тип("ДокументСсылка.РеализацияТоваровУслуг"));
ОткрытьФорму(
"РегистрСведений.СводныйРегистрДополнительныйКомментарий.ФормаСписка",
ПараметрыФормы
);
КонецПроцедуры
В модуле открываемой формы списка регистра сведений обработаем переданный параметр в обработчике ПриСозданииНаСервере и установим отбор на динамический список:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ФильтрПоТипуДокумента") Тогда
// Находим или создаем элемент отбора компоновки данных
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ТипДокумента");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Параметры.ФильтрПоТипуДокумента;
ЭлементОтбора.Использование = Истина;
// При необходимости можно запретить пользователю изменять этот отбор вручную
ЭлементОтбора.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
КонецЕсли;
КонецПроцедуры
Преимущества: Запрос динамического списка остается статичным, что позволяет платформе кэшировать план его выполнения в СУБД. Решение легко масштабируется на любое количество типов документов без изменения логики формы списка регистра.
---
Если мы не хотим выводить поле типа в колонки динамического списка или предпочитаем работать напрямую с параметрами схемы компоновки данных (СКД), то можем задействовать механизм фигурных скобок {}. Это позволит сделать условие отбора необязательным.
Рассмотрим структуру запроса динамического списка:
ВЫБРАТЬ
Рег.Период,
Рег.ДокументКомментарий,
Рег.Комментарий
ИЗ
РегистрСведений.СводныйРегистрДополнительныйКомментарий КАК Рег
{ГДЕ
(ТИПЗНАЧЕНИЯ(Рег.ДокументКомментарий) = &ПараметрТипДокумента)}
В коде обработчика ПриСозданииНаСервере формы регистра мы просто устанавливаем значение параметра, если он был передан:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ФильтрПоТипуДокумента") Тогда
Список.Параметры.УстановитьЗначениеПараметра(
"ПараметрТипДокумента",
Параметры.ФильтрПоТипуДокумента
);
КонецЕсли;
КонецПроцедуры
Почему это удобно: Конструкция {ГДЕ ...} гарантирует, что если форма списка открывается пользователем напрямую из интерфейса (и параметр ФильтрПоТипуДокумента не передан), СКД проигнорирует условие в фигурных скобках и выведет все имеющиеся записи без вызова исключений и ошибок СУБД.
---
Этот способ обсуждался участниками оригинальной темы на форуме. Он предполагает программную замену текста запроса динамического списка при открытии формы в зависимости от переданных параметров.
Передадим из формы документа имя метаданных в строковом формате:
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ИмяВидаДокумента", "РеализацияТоваровУслуг");
ОткрытьФорму("РегистрСведений.СводныйРегистрДополнительныйКомментарий.ФормаСписка", ПараметрыФормы);
В форме списка регистра переопределим текст запроса динамического списка на лету:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ИмяВидаДокумента") Тогда
ИмяДокумента = Параметры.ИмяВидаДокумента;
// Динамически конструируем текст запроса с использованием оператора ССЫЛКА
НовыйТекстЗапроса =
"ВЫБРАТЬ
| Рег.Период,
| Рег.ДокументКомментарий,
| Рег.Комментарий
|ИЗ
| РегистрСведений.СводныйРегистрДополнительныйКомментарий КАК Рег
|ГДЕ
| Рег.ДокументКомментарий ССЫЛКА Документ." + ИмяДокумента;
Список.ТекстЗапроса = НовыйТекстЗапроса;
КонецЕсли;
КонецПроцедуры
Особенности метода: Оператор ССЫЛКА работает на уровне СУБД максимально эффективно, так как транслируется в проверку конкретной таблицы-источника. Однако динамическая модификация текста запроса усложняет отладку кода, ухудшает читаемость и препятствует автоматическому обновлению схемы динамического списка при изменении метаданных.
---
Давайте подробно проанализируем важный нюанс производительности СУБД. При использовании виртуального поля с функцией ТИПЗНАЧЕНИЯ в секции ГДЕ, СУБД на низком уровне часто не может задействовать существующие индексы по измерению ДокументКомментарий. Это происходит из-за того, что СУБД вынуждена производить вычисления типа для каждой записи таблицы (операция Table Scan или сканирование индекса вместо быстрого поиска Index Seek).
Если в вашем регистре планируется хранить сотни тысяч или миллионы записей, использование способов 1 и 2 приведет к заметному замедлению открытия формы списка. В этом случае наиболее профессиональным решением будет добавление физического измерения ТипДокумента (тип: Строка, длина 150, или ссылка на специальный справочник видов документов).
Рассмотрим алгоритм реализации:
ТипДокументаСтрока с признаком Индексировать.
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Пример заполнения при записи через менеджер записи
ТекущийОбъект.ТипДокументаСтрока = ТекущийОбъект.ДокументКомментарий.Метаданные().Имя;
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ИмяВидаДокумента") Тогда
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ТипДокументаСтрока");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Параметры.ИмяВидаДокумента;
ЭлементОтбора.Использование = Истина;
КонецЕсли;
КонецПроцедуры
---
Если разработка ведется в типовой конфигурации на базе БСП (Библиотека Стандартных Подсистем), мы можем значительно сократить объем шаблонного кода по ручной генерации элементов отбора СКД. Для этого воспользуемся готовыми методами общего модуля ОбщегоНазначенияКлиентСервер.
Давайте посмотрим, как лаконично выглядит установка отбора в обработчике ПриСозданииНаСервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Sвойство("ФильтрПоТипуДокумента") Тогда
// Используем стандартный метод БСП для быстрой установки отбора
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(
Список.Отбор,
"ТипДокумента",
Параметры.ФильтрПоТипуДокумента
);
КонецЕсли;
КонецПроцедуры
Этот подход минимизирует количество строк кода, снижает вероятность опечаток при написании типов компоновки данных и делает код более стандартизированным для поддержки другими разработчиками.
---
Выбор конкретного метода зависит от архитектурных требований и планируемого объема данных в системе: