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