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

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

При работе с Системой компоновки данных (СКД) в «1С:Предприятие 8» разработчики часто сталкиваются с необходимостью обработать результат отчета программно. Вместо вывода в стандартный табличный документ данные требуется выгрузить во временную таблицу значений или дерево значений для последующего анализа. При реализации этой задачи нередко возникают две критические ошибки. Первая связана с ограничением платформы на вывод сложных структур настроек в коллекции, а вторая — со сбоем механизма расшифровки в управляемом приложении. Разберем обе ситуации подробно, выясним их причины и рассмотрим надежные варианты решения.

Часть 1. Вывод результатов СКД в универсальную коллекцию значений

Попытка выгрузить данные из СКД в таблицу или дерево значений стандартным кодом часто приводит к одной из двух ошибок:

  1. «Неизвестный тип макета» на этапе выполнения компоновки макета.
  2. «Не поддерживается вывод таблиц, диаграмм и вложенных отчетов в универсальную коллекцию значений» на этапе генерации макета компоновки.

Выясним причину первой ошибки. По умолчанию объект КомпоновщикМакетаКомпоновкиДанных при вызове метода Выполнить() ориентируется на генерацию макета для табличного документа. Если мы затем передаем этот макет в ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений, система выдает ошибку совместимости типов.

Для решения этой проблемы необходимо явно указать платформе, какой генератор макета следует использовать. Посмотрим на правильный шаблон инициализации:


КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
// Указываем тип генератора макета в пятом параметре метода Выполнить()
МакетКомпоновки = КомпоновщикМакета.Выполнить(
    СхемаКомпоновкиДанных, 
    Настройки, 
    ДанныеРасшифровки, , 
    Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений")
);

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

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

Перейдем ко второй ошибке, связанной с ограничением вывода таблиц и диаграмм. Почему платформа накладывает такое ограничение? Объект ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений предназначен исключительно для работы с плоскими структурами (строки детальных записей и линейные группировки) или простыми иерархическими структурами в случае дерева значений.

Если в настройках схемы компоновки (вкладка «Настройки» в конструкторе СКД) корневым элементом структуры является «Таблица» (кросс-таблица с динамическими колонками и строками) или «Диаграмма», система физически не может спроецировать эту многомерную матрицу на плоскую таблицу значений. В этом случае генератор макета аварийно завершает работу.

Стоит также учитывать, что при выводе в коллекцию значений платформа полностью игнорирует:

Из всех настроек оформления процессором коллекции учитываются только параметры расположения общих итогов по вертикали, авто-определение типов колонок и ограничение на количество записей.

Варианты обхода ограничения на вывод таблиц

Что делать, если пользователю на форму выводится сложная кросс-таблица, но в коде нам крайне необходимо получить рассчитанные ресурсы именно в формате таблицы значений? Рассмотрим три основных способа решения этой задачи.

Способ 1. Программная трансформация структуры настроек «на лету»

Мы можем программно скопировать текущие настройки отчета, полностью очистить их структуру и перестроить ее в плоский список детальных записей или группировок строк перед генерацией макета. Посмотрим на примере, как можно подменить вариант настроек или переформировать структуру:


// Получаем исходную схему и текущие настройки
СхемаКомпоновкиДанных = ЭтотОбъект.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
НастройкиКопия = Новый НастройкиКомпоновкиДанных;

// Вариант А: Загружаем альтернативный, заранее созданный плоский вариант настроек из схемы
ИмяВариантаДляВыгрузки = "ДляВыгрузкиВТЗ";
ВариантНастроек = СхемаКомпоновкиДанных.ВариантыНастроек.Найти(ИмяВариантаДляВыгрузки);
Если ВариантНастроек <> Неопределено Тогда
    НастройкиКопия = ВариантНастроек.Настройки;
Иначе
    // Вариант Б: Программное преобразование структуры "на лету"
    НастройкиКопия = ЭтотОбъект.КомпоновщикНастроек.ПолучитьНастройки();
    НастройкиКопия.Структура.Очистить();
    
    // Добавляем простую группировку детальных записей
    НоваяГруппировка = НастройкиКопия.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
    НоваяГруппировка.Использование = Истина;
    
    АвтоПоле = НоваяГруппировка.ВыбранныеПоля.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
    АвтоПоле.Использование = Истина;
КонецЕсли;

// Теперь выполняем стандартную компоновку с безопасными настройками
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(
    СхемаКомпоновкиДанных, 
    НастройкиКопия, , , 
    Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений")
);

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

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

Способ 2. Программный парсинг областей Табличного Документа

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

Способ 3. Прямое выполнение запроса СКД

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

Часть 2. Исправление ошибки «Неправильный путь к файлу 'ДанныеРасшифровкиКомпоновкиДанных'»

Перейдем ко второй распространенной проблеме, которая возникает при интерактивной работе с отчетами на управляемых формах. При повторном формировании программно созданного отчета или при попытке дважды кликнуть по ячейке для вызова расшифровки система выдает ошибку: «Неправильный путь к файлу 'ДанныеРасшифровкиКомпоновкиДанных'».

Разберем детально механизм работы расшифровки в управляемом приложении. В обычных формах (толстый клиент) переменная, хранящая расшифровку, представляла собой тяжелый контекстный объект типа ДанныеРасшифровкиКомпоновкиДанных. В управляемых формах (тонкий и веб-клиент) прямая передача таких объектов между клиентом и сервером невозможна.

По этой причине реквизит управляемой формы с именем ДанныеРасшифровки имеет простой тип Строка. В нем платформа сохраняет не сам объект, а временный уникальный адрес (URL-путь) во временном хранилище, где физически сериализован и сохранен реальный объект расшифровки.

Проанализируем типичный ошибочный код на сервере, приводящий к сбою:


&НаСервере
Процедура ПечатьНажатиеНаСервере()
    СхемаКомпоновкиДанных = ПолучитьОбщуюСхему();
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    
    // ОШИБКА: Объявление локальной переменной перекрывает строковый реквизит формы!
    ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных; 
    
    Настройки = Отчет.КомпоновщикНастроек.Настройки;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
    // Вывод в ТабличныйДокумент...
КонецПроцедуры

Что происходит при выполнении этого ошибочного кода?

  1. Создается локальная переменная ДанныеРасшифровки объектного типа. Она маскирует контекстный строковый реквизит формы с тем же именем.
  2. Метод Выполнить() отрабатывает нормально, так как он принимает объект расшифровки.
  3. По завершении серверного вызова локальная переменная уничтожается сборщиком мусора, так как время ее жизни ограничено выполнением процедуры.
  4. На клиенте строковый реквизит формы ДанныеРасшифровки остается пустым или содержит старый невалидный адрес.
  5. При попытке пользователя расшифровать ячейку на клиенте платформа обращается по пустому или уничтоженному адресу во временном хранилище и генерирует ошибку неверного пути к файлу.

Правильный шаблон программного вывода отчета с расшифровкой

Чтобы избежать этой ошибки, необходимо строго соблюдать три правила:

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

Посмотрим на пример правильной реализации серверного метода печати:


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

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

← На главную