Разберем классическую ситуацию, с которой часто сталкиваются разработчики при поддержке типовых конфигураций 1С (таких как ЗУП, ЗГУ, ERP и других). Вы открываете отчет, построенный на системе компоновки данных (СКД), переходите в схему компоновки и видите там практически пустой текст запроса или простейший шаблон. Весь основной запрос со множеством временных таблиц, условий и соединений собирается динамически в кодовой части модуля отчета — обычно в предопределенной процедуре ПриКомпоновкеРезультата.
Такой подход позволяет платформе гибко управлять структурой запроса в зависимости от выбранных пользователем настроек, но создает серьезную проблему для отладки. Мы не можем просто скопировать запрос из схемы и вставить его в консоль запросов, так как на момент открытия схемы этого запроса еще не существует, а временные таблицы создаются и уничтожаются прямо во время выполнения кода. В этой статье мы подробно разберем, как эффективно отлаживать такие отчеты, как извлечь временные таблицы прямо из отладчика и какие вспомогательные инструменты могут облегчить нам жизнь.
Начнем с возможностей, которые предоставляет сама платформа 1С:Предприятие. Если во время выполнения отчета у вас в отладчике есть доступ к объекту типа Запрос, в котором уже проинициализирован менеджер временных таблиц, мы можем просмотреть содержимое этих таблиц на лету, не изменяя конфигурацию.
Для этого установим точку останова в коде после того, как пакет запросов (или его часть) был выполнен, но менеджер временных таблиц еще не уничтожен. Откроем окно «Вычислить выражение» (сочетание клавиш Shift+F9) или воспользуемся панелью «Табло».
Вариант А. Получение данных по индексу таблицы
Если мы знаем порядковый номер временной таблицы в пакете, мы можем обратиться к ней напрямую по индексу. Введем следующее выражение:
Запрос.МенеджерВременныхТаблиц.Таблицы[0].ПолучитьДанные().Выгрузить()
После вычисления этого выражения платформа вернет объект ТаблицаЗначений. Чтобы детально рассмотреть ее строки и колонки, достаточно нажать клавишу F2 на клавиатуре — откроется удобное стандартное окно просмотра коллекций 1С.
Вариант Б. Получение данных по имени временной таблицы
Часто индексы таблиц могут меняться при изменении логики программы, поэтому гораздо надежнее обращаться к ним по имени. Используем метод поиска по имени:
Запрос.МенеджерВременныхТаблиц.Таблицы.Найти("ИмяВременнойТаблицы").ПолучитьДанные().Выгрузить()
Этот способ гарантирует, что мы получим данные именно той таблицы, которая нас интересует, даже если структура запроса претерпела динамические изменения.
Вариант В. Выполнение всего пакета запросов с промежуточными данными
Если нам нужно выполнить запрос заново и сразу посмотреть результаты всех временных таблиц, обычный метод ВыполнитьПакет() нам не очень поможет, так как для временных таблиц он возвращает только количество затронутых строк. Вместо этого применим специальный платформенный метод:
Запрос.ВыполнитьПакетСПромежуточнымиДанными()[ИндексВременнойТаблицы].Выгрузить()
Этот метод выполняет весь пакет запросов и возвращает массив результатов, где для каждого запроса пакета (включая создание ВТ) содержится полноценная таблица с данными.
Хитрость: Подмена текста запроса прямо в отладчике
Представим ситуацию: нам нужно выполнить произвольный запрос к уже созданным в памяти временным таблицам. Мы можем сделать это прямо в окне вычисления выражений за несколько простых шагов:
Запрос.Текст = "ВЫБРАТЬ * ИЗ ИмяВременнойТаблицы Где ВажноеПоле = &ЗначениеПараметра"
Запрос.Выполнить().Выгрузить()Запрос.Текст.СКД устроена таким образом, что исходный текст запроса из схемы компоновки претерпевает значительные оптимизации перед отправкой в СУБД. Платформа убирает неиспользуемые поля, добавляет отборы, наложенные пользователем, и преобразует конструкцию запроса. Чтобы увидеть именно тот финальный запрос, который реально уходит на сервер СУБД, нам нужно заглянуть внутрь объекта МакетКомпоновкиДанных.
Разберем по шагам, как перехватить этот макет:
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки);
Для получения реального текста запроса введем выражение:
МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос
Примечание: Имя набора данных (НаборДанных1) может отличаться в зависимости от того, как вы назвали его в вашей схеме компоновки.
Для получения параметров запроса, которые СКД автоматически рассчитала и подготовила к передаче, выполним выражение:
МакетКомпоновки.ЗначенияПараметров
В этой коллекции будут находиться абсолютно все параметры (включая системные, такие как периоды, авто-отборы и пользовательские настройки) с их реальными значениями. Это решает проблему со множеством скрытых параметров, о которой часто упоминают разработчики при анализе сложных отчетов.
Инструменты разработчика — это мощный комплекс программных средств для платформы 1С, который существенно упрощает жизнь программиста. Одной из ключевых функций этой подсистемы является отладочная функция От(). Она позволяет мгновенно визуализировать и исследовать сложные объекты прямо в процессе выполнения кода.
Разберем два сценария использования функции От() для отладки СКД.
Сценарий 1. Отладка схемы и настроек компоновки
Если мы находимся в точке останова, где схема компоновки уже программно модифицирована в коде, но макет еще не сгенерирован, мы можем передать схему и настройки в функцию От() следующим образом:
От(СхемаКомпоновки, НастройкаКомпоновки, ВнешниеНаборыДанных)
Эта команда автоматически перехватит текущее состояние схемы, применит указанные настройки и внешние наборы данных, после чего откроет специализированную форму Консоли компоновки данных. Из этой консоли мы сможем легко перейти в стандартную Консоль запросов, где все результирующие запросы пакета будут разложены по полочкам.
Сценарий 2. Отладка готового макета компоновки
Если отчет формирует макет динамически, меняет его структуру "на лету" и только потом передает его процессору компоновки, нам нужно анализировать именно готовый макет. Для этого в точке останова вызовем функцию:
От(МакетКомпоновкиДанных)
Эта команда откроет макет компоновки в консоли запросов со всеми заполненными параметрами, временными таблицами и структурой связей. Нам больше не придется вручную вытаскивать параметры и сопоставлять их с текстом запроса.
Если по каким-то причинам использование внешних инструментов невозможно (например, на закрытом сервере клиента или в режиме веб-клиента), мы можем написать собственную вспомогательную процедуру для выгрузки данных. Мы можем внедрить ее непосредственно в модуль объекта нашего отчета и вызывать в критических точках процедуры ПриКомпоновкеРезультата.
Рассмотрим пример такой процедуры:
Процедура ПоказатьВременнуюТаблицу(МенеджерВТ, ИмяТаблицы) Экспорт
ЗапросОтладки = Новый Запрос;
ЗапросОтладки.МенеджерВременныхТаблиц = МенеджерВТ;
ЗапросОтладки.Текст = "ВЫБРАТЬ * ИЗ " + ИмяТаблицы;
Попытка
ТЗРезультат = ЗапросОтладки.Volnit().Выгрузить();
// Запишем ее в XML для анализа в Журнале регистрации
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписатьXML(ЗаписьXML, ТЗРезультат);
ТекстXML = ЗаписьXML.Закрыть();
ЗаписьЖурналаРегистрации("ОтладкаСКД",
УровеньЖурналаРегистрации.Информация,
,
,
"Данные таблицы " + ИмяТаблицы + ": " + ТекстXML);
Исключение
ВызватьИсключение "Ошибка при выгрузке временной таблицы: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Чтобы воспользоваться этим решением, нам достаточно вставить вызов этой процедуры в коде формирования данных:
ПоказатьВременнуюТаблицу(НашМенеджерВТ, "ВТ_ИтоговыеСуммы");
Этот метод особенно удобен при фоновом выполнении задач на сервере, когда мы не можем напрямую подключиться интерактивным отладчиком к сеансу. Мы просто заглядываем в Журнал регистрации и анализируем структуру нашей таблицы.
Часто при программной подготовке данных разработчики создают менеджер временных таблиц в кодовой части общего модуля, наполняют его данными, а затем передают этот менеджер в СКД. При этом в самой схеме компоновки прописывается простой запрос-заглушка к этой таблице.
Если вы столкнулись с такой архитектурой, помните, что вы можете контролировать процесс на этапе инициализации процессора компоновки данных. Обратите внимание на метод Инициализировать() объекта ПроцессорКомпоновкиДанных:
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
Передача менеджера временных таблиц в свойствах макета позволяет связать контекст выполнения вашего программного кода с ядром СКД. При отладке всегда проверяйте состояние менеджера ВТ перед его передачей в процессор компоновки. Если таблицы пустые на входе — проблема кроется в процедурах подготовки данных, а не в самой схеме СКД.
Используя комбинацию платформенных методов (таких как ВыполнитьПакетСПромежуточнымиДанными()), возможности "Инструментов разработчика" и перехват макета компоновки, вы сможете быстро локализовать любую ошибку в коде или запросе, сэкономив часы рабочего времени.