Как передать объект Запрос и Менеджер временных таблиц с сервера на клиент в 1С

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

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

Разберем подробно, почему возникает эта проблема, как устроена работа с серверным контекстом и как правильно организовать передачу данных запроса для отладки.

Почему нельзя передать объект Запрос и Менеджер временных таблиц напрямую

Выясним причину такого поведения платформы. Объекты Запрос и МенеджерВременныхТаблиц являются несериализуемыми контекстными объектами. Они жестко привязаны к текущему серверному контексту и сеансу соединения с СУБД:

  1. Контекст СУБД: Временные таблицы физически создаются и хранятся на стороне сервера баз данных в рамках конкретной сессии. Менеджер временных таблиц лишь хранит дескрипторы (ссылки) на эти таблицы. При завершении серверного вызова или уничтожении объекта менеджер автоматически очищает временные таблицы в СУБД.
  2. Кластерная архитектура: В клиент-серверном варианте разные серверные вызовы могут обрабатываться разными рабочими процессами (rphost) или даже разными серверами кластера. Передать между ними «живой» указатель на память или соединение невозможно.
  3. Доступность типов: Тип Запрос недоступен на тонком клиенте. Передавать между клиентом и сервером разрешено только сериализуемые типы (примитивные типы, структуры, соответствия, таблицы значений, массивы и т. д.).
  4. Ограничения управляемых форм: В управляемом приложении методы открытия форм (например, ОткрытьФорму) не могут вызываться на сервере, так как работа с пользовательским интерфейсом возможна только на клиенте.

Архитектура правильного решения

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

  1. На сервере (в месте отладки): Извлекаем из запроса текст, копируем параметры в сериализуемую структуру, а все таблицы из МенеджерВременныхТаблиц универсально выгружаем в обычные объекты ТаблицаЗначений.
  2. Помещение в хранилище: Упаковываем полученные данные в общую структуру и сохраняем её через ПоместитьВоВременноеХранилище, возвращая клиенту строковый адрес.
  3. На клиенте: Получаем адрес хранилища и вызываем открытие формы консоли запросов, передавая этот адрес в параметрах формы.
  4. В консоли запросов (на сервере формы): Извлекаем структуру из временного хранилища, заполняем текст и параметры запроса, создаем новый МенеджерВременныхТаблиц и загружаем в него выгруженные таблицы значений с помощью служебных запросов с конструкцией ПОМЕСТИТЬ.

Шаг 1. Универсальная выгрузка запроса и МВТ на сервере

Рассмотрим пример экспортной функции в общем серверном модуле, которая подготавливает данные запроса к передаче. Обратите внимание, что для выгрузки таблиц из менеджера временных таблиц не требуется знать их имена заранее — мы можем обойти коллекцию Таблицы объекта МенеджерВременныхТаблиц.


Функция ПодготовитьДанныеЗапросаДляОтладки(Знач ИсходныйЗапрос, Знач УникальныйИдентификаторФормы = Неопределено) Экспорт

    ДанныеЗапроса = Новый Структура;
    ДанныеЗапроса.Вставить("Текст", ИсходныйЗапрос.Текст);
    
    // 1. Копируем параметры запроса
    СтруктураПараметров = Новый Структура;
    Для Каждого КлючИЗначение Из ИсходныйЗапрос.Параметры Цикл
        СтруктураПараметров.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
    КонецЦикла;
    ДанныеЗапроса.Вставить("Параметры", СтруктураПараметров);
    
    // 2. Универсально выгружаем таблицы из Менеджера временных таблиц
    ТаблицыМВТ = Новый Структура;
    Если ИсходныйЗапрос.МенеджерВременныхТаблиц <> Неопределено Тогда
        Для Каждого ЭлементТаблицы Из ИсходныйЗапрос.МенеджерВременныхТаблиц.Таблицы Цикл
            ИмяВТ = ЭлементТаблицы.Имя;
            ТЗДанные = ЭлементТаблицы.ПолучитьДанные().Выгрузить();
            ТаблицыМВТ.Вставить(ИмяВТ, ТЗДанные);
        КонецЦикла;
    КонецЕсли;
    ДанныеЗапроса.Вставить("ТаблицыМВТ", ТаблицыМВТ);
    
    // 3. Помещаем упакованные сериализуемые данные во временное хранилище
    АдресХранилища = ПоместитьВоВременноеХранилище(ДанныеЗапроса, УникальныйИдентификаторФормы);
    
    Возврат АдресХранилища;

КонецФункции

Шаг 2. Открытие консоли на клиенте

Проанализируем вызов на стороне клиента. Клиентский код получает адрес во временном хранилище и открывает форму обработки:


&НаКлиенте
Процедура ОткрытьЗапросВКонсоли(АдресХранилища)

    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("АдресДанныхЗапроса", АдресХранилища);
    
    ОткрытьФорму("Обработка.КонсольЗапросов.Форма", ПараметрыОткрытия);

КонецПроцедуры

Шаг 3. Восстановление запроса и МВТ в форме консоли

Посмотрим, как в модуле формы консоли запросов (в событии ПриСозданииНаСервере) восстановить состояние исходного запроса и заново наполнить МенеджерВременныхТаблиц:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Если Параметры.Свойство("АдресДанныхЗапроса") И ЭтоАдресВременногоХранилища(Параметры.АдресДанныхЗапроса) Тогда
        
        ДанныеЗапроса = ПолучитьИзВременногоХранилища(Параметры.АдресДанныхЗапроса);
        УдалитьИзВременногоХранилища(Параметры.АдресДанныхЗапроса);
        
        // Устанавливаем текст запроса в реквизит формы
        Объект.ТекстЗапроса = ДанныеЗапроса.Текст;
        
        // Создаем новый менеджер и восстанавливаем временные таблицы
        НовыйМВТ = Новый МенеджерВременныхТаблиц;
        
        Для Каждого ЭлементВТ Из ДанныеЗапроса.ТаблицыМВТ Цикл
            ИмяВТ = ЭлементВТ.Ключ;
            ТЗ_Данные = ЭлементВТ.Значение;
            
            // Загружаем ТЗ во временную таблицу через служебный запрос
            СлужебныйЗапрос = Новый Запрос;
            СлужебныйЗапрос.МенеджерВременныхТаблиц = НовыйМВТ;
            СлужебныйЗапрос.Текст = 
                "ВЫБРАТЬ * ПОМЕСТИТЬ " + ИмяВТ + " ИЗ &ВходящаяТаблица КАК Источник";
            СлужебныйЗапрос.УстановитьПараметр("ВходящаяТаблица", ТЗ_Данные);
            СлужебныйЗапрос.Выполнить();
        КонецЦикла;
        
        // Передаем параметры и МВТ в рабочий объект консоли
        // (в зависимости от структуры используемой консоли запросов)
        ЗаполнитьПараметрыКонсоли(ДанныеЗапроса.Параметры, НовыйМВТ);
        
    КонецЕсли;

КонецПроцедуры

Быстрый просмотр временных таблиц в отладчике

Если нет необходимости открывать отдельную консоль, а нужно лишь быстро оценить содержимое сформированной временной таблицы в процессе отладки, воспользуемся окном вычисления выражений платформы (Shift + F9):


Запрос.МенеджерВременныхТаблиц.Таблицы.Найти("ИмяНужнойТаблицы").ПолучитьДанные().Выгрузить()

Либо обратимся по индексу таблицы в коллекции:

Запрос.МенеджерВременныхТаблиц.Таблицы[0].ПолучитьДанные().Выгрузить()

Метод ПолучитьДанные().Выгрузить() возвращает стандартную таблицу значений, которую отладчик 1С отображает в удобном табличном виде со всеми колонками и типами данных.

← На главную