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