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