Как программно применить отборы из одной схемы СКД к другой?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Рассмотрим ситуацию, с которой часто сталкиваются разработчики при программной работе с Системой Компоновки Данных (СКД). Задача состоит в следующем: необходимо создать обработку, цель которой — отбирать документы с помощью различных отборов для их последующего редактирования. Для этого мы создаем две схемы компоновки данных. Первая схема описывает отборы, вторая — содержит сам запрос к базе данных (например, к регистру). Результат выполнения второй схемы, с учетом отборов из первой, выгружается в таблицу значений на форме.

Посмотрим на пример кода инициализации отборов на форме:


ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
СхемаСКД = ОбработкаОбъект.ПолучитьМакет("Отборы");
АдресСхемы = ПоместитьВоВременноеХранилище(СхемаСКД, УникальныйИдентификатор);
ИсточникДоступныхНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы);
Объект.КомпоновщикНастроек.Инициализировать(ИсточникДоступныхНастроек);
Объект.КомпоновщикНастроек.ЗагрузитьНастройки(СхемаСКД.НастройкиПоУмолчанию);

Далее, для получения результатов по второй схеме, мы применяем настройки компоновщика, полученные на предыдущем шаге:


ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
СхемаКомпоновкиДанных = ОбработкаОбъект.ПолучитьМакет("ЗапросИнформации"); 
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; 
МакетКомпоновкиДанных = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных,
    ОбработкаОбъект.КомпоновщикНастроек.Настройки, , ,
    Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));  
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных); 
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ТаблицаОтобранныхЭлементов = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаОтобранныхЭлементов);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);

На первый взгляд, реализация выглядит логичной. Однако при тестировании выясняется, что для одних документов отбор работает корректно и таблица заполняется, а для других — возвращается пустой результат, несмотря на наличие движений в регистре. Проанализируем причины такого поведения и разберем способы решения.

Почему отбор может не применяться?

Когда мы передаем КомпоновщикНастроек.Настройки от одной схемы в метод Выполнить КомпоновщикМакета для другой схемы, платформа пытается сопоставить данные. Если результат пустой, на это могут влиять несколько факторов:

  1. Проблема с левым соединением: Как отмечается в сообщении темы, наложенный глобальный отбор на внешнюю таблицу может превратить левое соединение наборов данных во внутреннее. Если данные по отбору не находятся в одной из связываемых таблиц, строка отсекается целиком.
  2. Несовпадение путей к данным: СКД опирается на внутренние пути полей (свойство ЛевоеЗначение элемента отбора). Если структура наборов, имена полей или их псевдонимы в первой и второй схемах отличаются, отбор будет проигнорирован или сработает непредсказуемо. Метод Выполнить строго привязан к схеме, переданной первым параметром.
  3. Глобальный отбор по виртуальным таблицам: Если вторая схема обращается к виртуальным таблицам регистров (Остатки, Обороты), наложение отбора на уровне общих настроек компоновщика часто работает некорректно. СКД может применять отбор уже после формирования полной таблицы. Отборы к виртуальным таблицам должны применяться через параметры самой виртуальной таблицы.
  4. Особенности составных типов: Если поле (например, Регистратор) имеет составной тип, а в отборе передается ссылка на документ, тип которого физически не участвует в запросе второй схемы, СКД не сможет сопоставить типы и вернет пустой результат.

Способы решения проблемы

Разберем несколько подходов, которые помогут корректно применить фильтрацию.

1. Программный перенос отборов

Не передавайте настройки от первой схемы во вторую напрямую целиком. Вместо этого программно переберите коллекцию элементов отбора первой схемы и перенесите их во вторую.

Вам нужно обойти коллекцию КомпоновщикНастроек.Настройки.Отбор.Элементы, считать свойства ЛевоеЗначение, ВидСравнения и ПравоеЗначение, а затем программно добавить аналогичные элементы в структуру отбора второй схемы перед генерацией макета компоновки. Это исключит конфликт служебных настроек.

2. Параметризация запроса вместо отбора

Если вам нужно фильтровать данные по конкретному документу или периоду, надежнее использовать параметры. Во второй схеме в тексте запроса вынесите условие в блок ГДЕ, например: ГДЕ Регистратор = &ДокументОтбора. При выполнении кода считывайте выбранный документ из настроек первой схемы и устанавливайте его как значение параметра в КомпоновщикНастроек.Настройки.ПараметрыДанных второй схемы. Это гарантирует, что фильтр применится на уровне СУБД, а не после формирования выборки.

3. Настройка макета и отключение автозаполнения

Посмотрим на макет компоновки сгенерированного запроса. В некоторых случаях СКД может самостоятельно добавлять условия, которые ломают логику. Попробуйте снять флажок Автозаполнение в конструкторе запроса второй схемы и вручную опишите расширение языка запросов для СКД (укажите поля, параметры и условия отбора в фигурных скобках {}). Это даст полный контроль над тем, куда именно СКД будет подставлять ваш отбор.

4. Использование одной схемы или динамического списка

Если бизнес-логика позволяет, откажитесь от использования двух схем. Вы можете создать единую СКД, где первый набор данных будет реальным запросом к регистру, а второй (вспомогательный) — набором-объектом, содержащим только доступные поля для фильтрации. Настроив связи между наборами, вы сможете использовать единый компоновщик настроек.

Также, если конечная цель — просто вывести отобранные документы пользователю на форму, рассмотрите использование реквизита типа ДинамическийСписок с произвольным запросом. Этот механизм "из коробки" поддерживает типовые пользовательские отборы, автоматически формирует оптимальные запросы и не требует сложного программирования процессоров вывода СКД в коллекции значений.

При использовании ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений помните, что тип генератора макета для коллекции значений накладывает ограничения: отбор должен быть плоским, иначе итоговая таблица может сформироваться пустой или с потерей строк.

← На главную