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