При разработке сложных отчетов на схеме компоновки данных (СКД) часто возникает необходимость объединить стандартные запросы к базе данных с внешними источниками информации. В качестве такого источника обычно выступает ТаблицаЗначений, сформированная программно. Однако при связывании встроенных запросов и внешних наборов данных разработчики регулярно сталкиваются с неочевидными ошибками компоновки. Две самые распространенные из них — это «Не найден внешний набор данных» и «Не найдено поле замены».
В этой статье мы подробно разберем, почему возникают эти ошибки, проанализируем реальный пример некорректного кода инициализации процессора компоновки и рассмотрим пошаговый алгоритм правильной настройки связей наборов данных.
Рассмотрим ситуацию, с которой столкнулся автор темы. В процедуре вывода отчета подготавливается внешняя таблица значений, которая затем передается в структуру для инициализации компоновщика. Однако при формировании отчета система выдает ошибку: «Не найден внешний набор данных».
Давайте внимательно изучим фрагмент кода, содержащий критическую ошибку:
пПериод = Настройки.ПараметрыДанных.Элементы.Найти("Период");
Если пПериод <> Неопределено Тогда
ТабКолУб = ПолучитьТЗКолУбыли(пПериод.Значение);
ВнешнийНаборДанных = Новый Структура("ТабКолУб", ТабКолУб);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешнийНаборДанных);
Иначе
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
КонецЕсли;
// КРИТИЧЕСКАЯ ОШИБКА:
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
Выясним причину сбоя. В блоке Если ... КонецЕсли логика написана верно: если параметр периода найден, то создается структура ВнешнийНаборДанных, которая передается в метод Инициализировать объекта ПроцессорКомпоновкиДанных.
Однако сразу после этого блока разработчик по ошибке (например, в результате некорректного копирования кода) повторно создает объект ПроцессорКомпоновкиДанных и инициализирует его заново, но уже без параметров внешнего набора. В итоге предыдущая успешная инициализация полностью затирается, и СКД при выводе закономерно сообщает, что объявленный в схеме внешний набор данных ТабКолУб не был передан.
Чтобы избежать подобных ошибок, напишем чистый и надежный шаблон для вывода отчета. Обратите внимание, что мы должны четко контролировать наполнение структуры внешних наборов данных и инициализировать процессор компоновки строго один раз.
Процедура ВывестиСКДВТабличныйДокумент(МакетСКД, ТабличныйДокумент, КомпоновщикНастроек) Экспорт
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(МакетСКД, Настройки);
// Подготавливаем структуру для внешних наборов данных
ВнешниеНаборыДанных = Новый Структура;
// Получаем период и формируем таблицу значений
пПериод = Настройки.ПараметрыДанных.Элементы.Найти("Период");
Если пПериод <> Неопределено И ЗначениеЗаполнено(пПериод.Значение) Тогда
ТаблицаКоличества = ПолучитьТЗКолУбыли(пПериод.Значение);
Иначе
// Создаем пустую таблицу с аналогичной структурой во избежание ошибок компоновки
ТаблицаКоличества = Новый ТаблицаЗначений;
ТаблицаКоличества.Колонки.Добавить("Организация");
ТаблицаКоличества.Колонки.Добавить("Контрагент");
ТаблицаКоличества.Колонки.Добавить("Период");
ТаблицаКоличества.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
КонецЕсли;
// Важно: имя ключа в структуре должно СТРОГО совпадать с именем Набора данных - объекта в СКД
ВнешниеНаборыДанных.Вставить("ТабКолУб", ТаблицаКоличества);
// Инициализируем процессор компоновки ОДИН раз
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);
// Выводим результат в табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Вторая проблема, описанная автором: при попытке добавить в связь наборов или в выводимые поля числовой показатель (в данном случае — Количество) возникает ошибка «Не найдено поле замены Количество».
Давайте детально проанализируем причины этой ошибки и способы ее локализации:
Количество, а в коде колонка таблицы значений создана как количество или КОЛИЧЕСТВО, СКД выдаст ошибку отсутствия поля замены.Организация, Контрагент, Период) не сопоставляются, обязательная связь приводит к фатальному сбою компоновки макета. Снимите флаг «Обязательная» в строке связи наборов — это сделает соединение аналогичным левому соединению (Left Join) в SQL, и отчет сформируется без ошибок, даже если внешние данные пусты.Таблица.Колонки.Добавить("Количество")), система может передать туда значения типа Неопределено или типы, не поддающиеся сравнению, что приведет к краху алгоритмов сопоставления полей связи в СКД.Если ваш отчет СКД не формируется или выдает ошибки сопоставления полей, выполните по шагам следующие действия:
ПриКомпоновкеРезультата обязательно установлена инструкция СтандартнаяОбработка = Ложь;. Без нее платформа попытается сформировать отчет стандартными средствами без передачи вашей таблицы значений.ВнешниеНаборыДанных.Вставить("ИмяНабора", ТЗ) полностью совпадает с полем «Имя объекта» в свойствах набора данных СКД (тип «Набор данных - объект»).ОписаниеТипов при добавлении колонок в ТЗ.Организация, Контрагент и Период снят флаг «Обязательное условие связи» (или «Обязательная связь»).Соблюдение этих правил и аккуратное ведение кода инициализации процессора компоновки данных позволят вам успешно связывать любые внешние таблицы значений со стандартными наборами данных СКД, избегая трудночитаемых ошибок платформы.