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