Как исправить ошибку «Не найден внешний набор данных» при инициализации процессора компоновки данных в 1С?

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

При программном формировании отчетов на базе системы компоновки данных (СКД) разработчики часто сталкиваются с ошибкой инициализации процессора компоновки. Разберем типичную ситуацию, когда при выполнении метода ПроцессорКомпоновкиДанных.Инициализировать() возникает исключение: «Ошибка создания набора данных "..." по причине: Не найден внешний набор данных "..."».

Анализ проблемы и причин возникновения ошибки

Проанализируем фрагмент программного кода, в котором выполняется подготовка и передача данных в схему компоновки данных:


Если ДанныеОтчета = Неопределено Тогда
    ТЗПроектнаяСтатистика = ПолучитьТекстЗапроса();
Иначе
    ТЗПроектнаяСтатистика = ДанныеОтчета;
КонецЕсли;    

Если ТЗПроектнаяСтатистика = Неопределено Тогда
    Возврат;    
КонецЕсли;

Настройки = КомпоновщикНастроек.Настройки;

ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТЗПроектнаяСтатистика", ТЗПроектнаяСтатистика);

КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);

ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);

Посмотрим на то, что возвращает функция ПолучитьТекстЗапроса(). Внутри этой функции создается объект ТаблицаЗначений, описываются типы колонок, но затем динамически формируется текст запроса, и в конце функции указано:

Возврат ТекстЗапроса;

В результате в структуру ВнешниеНаборыДанных по ключу "ТЗПроектнаяСтатистика" вместо реальной таблицы или результата запроса помещается обычная Строка. Платформа 1С не может использовать строку как источник данных для набора данных типа «Объект» и генерирует исключение, сообщая, что внешний набор данных не найден.

Выделим основные причины, которые приводят к этой ошибке:

  1. Несоответствие типа переданного значения: значением элемента структуры внешних наборов данных может быть только ТаблицаЗначений, РезультатЗапроса или ДеревоЗначений. Если передана строка, число, массив или Неопределено, СКД не распознает источник данных.
  2. Несовпадение имени объекта данных: ключ в структуре ВнешниеНаборыДанных должен в точности (с соблюдением регистра) совпадать со свойством «Имя объекта, содержащего данные» в настройках набора данных типа «Объект» в схеме СКД (а не с именем самого набора данных в дереве схемы).

Способ 1. Выполнение запроса и передача результата в СКД

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

Посмотрим на пример правильной реализации функции получения данных:


Функция ПолучитьДанныеДляОтчета() Экспорт

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

КонецФункции

Обратим внимание: передача напрямую объекта РезультатЗапроса предпочтительнее выгрузки в ТаблицаЗначений через Выгрузить(), так как это снижает нагрузку на оперативную память сервера за счет отсутствия промежуточного дублирования данных.

Теперь скорректируем процедуру формирования отчета:


ТабДок.Очистить();     
    
Если ДанныеОтчета = Неопределено Тогда
    ДанныеДляСКД = ПолучитьДанныеДляОтчета();
Иначе
    ДанныеДляСКД = ДанныеОтчета;
КонецЕсли;    

Если ДанныеДляСКД = Неопределено Тогда
    Возврат;    
КонецЕсли;

Настройки = КомпоновщикНастроек.ПолучитьНастройки();

// Имя ключа структуры должно точно соответствовать имени объекта в схеме СКД
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТЗПроектнаяСтатистика", ДанныеДляСКД);

КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);

ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);

Способ 2. Перенос запроса внутрь схемы СКД (альтернативный вариант)

Рассмотрим альтернативный архитектурный подход. Ручная склейка текста запроса в коде и последующая передача таблицы значений во внешний набор часто является избыточной. Если запрос строится к стандартным таблицам базы данных 1С, целесообразно перенести запрос непосредственно в СКД, создав набор данных типа «Запрос».

Преимущества такого подхода:

  1. Автоматическая оптимизация запроса: платформа выбирает из базы только те поля и соединения таблиц, которые реально выводятся в отчет или используются в отборах.
  2. Штатная работа с иерархией: проверка условий вида В ИЕРАРХИИ и вывод иерархических группировок выполняются на уровне СУБД, а не средствами виртуальных таблиц СКД в оперативной памяти.
  3. Упрощение кода модуля: отпадает необходимость вручную объявлять структуры внешних наборов данных, перехватывать параметры и управлять инициализацией процессора компоновки данных.
← На главную