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