Как передать временные таблицы между вызовами сервера в 1С?

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

При разработке сложных обработок в 1С:Предприятие 8.3 часто возникает задача разделения логики на этапы. Например, по одной кнопке мы загружаем и рассчитываем данные, а по второй — записываем их в базу. Если расчеты сложные и используют запросы с временными таблицами, возникает естественное желание: не формировать эти таблицы заново при нажатии второй кнопки, а использовать уже готовые.

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

Суть проблемы: Жизненный цикл временных таблиц

Давайте проанализируем ситуацию, описанную в задаче. У нас есть два действия:

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

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

Рассмотрим, как устроена архитектура платформы:

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

Решение 1: Использование Временного хранилища (Рекомендуемый способ)

Наиболее универсальным и "чистым" с точки зрения архитектуры способом является сохранение данных в ВременноеХранилище. Давайте разберем этот алгоритм по шагам.

Идея заключается в том, чтобы не хранить сами временные таблицы (что невозможно), а хранить их содержимое в виде ТаблицаЗначений в оперативной памяти сервера или на диске (во временном хранилище), и восстанавливать их при необходимости.

Шаг 1. Формирование данных (Кнопка 1)

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


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

Шаг 2. Восстановление данных (Кнопка 2)

При нажатии второй кнопки мы проверяем, есть ли сохраненный адрес, получаем из него таблицу значений и снова загружаем её в запрос. СУБД обрабатывает такие операции очень быстро.


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

Анализ производительности и "Двойной расход памяти"

В обсуждении часто возникает вопрос: не будет ли это работать медленно из-за того, что мы гоняем данные из ВТ в ТЗ и обратно? Давайте проанализируем.

Миф о двойном расходе: Некоторые считают, что хранить данные и в хранилище, и в БД накладно. Однако, как верно замечено экспертами, ВременноеХранилище оптимизировано для таких задач. Данные сериализуются и хранятся на сервере приложений.

Реальная скорость: Операция Выгрузить() и загрузка параметра &ТЗ в запрос происходит в оперативной памяти (если объемы не гигантские). Для объема данных, озвученного в задаче (20 таблиц по 25 строк, или даже тысячи строк), время сериализации и десериализации составит доли миллисекунд. Это несопоставимо быстрее, чем заново читать файл с диска, парсить его и выполнять сложные вычисления.

Поэтому опасаться "лишних движений" данных в данном случае не стоит — это плата за отсутствие состояния (Stateless) между вызовами сервера, и эта плата минимальна.

Решение 2: Хранение в реквизитах формы

Если структура ваших временных таблиц жесткая (вы точно знаете колонки и типы заранее) и объем данных невелик, можно использовать реквизиты формы.

  1. Создайте на форме реквизит типа ТаблицаЗначений (например, ДанныеДляЗаписи) с нужными колонками.
  2. В первой процедуре заполните этот реквизит: ДанныеДляЗаписи.Загрузить(ТЗ_Результат).
  3. Во второй процедуре этот реквизит уже будет доступен в контексте, так как данные формы "путешествуют" между клиентом и сервером.

Преимущества: Не нужно возиться с адресами временного хранилища. Данные всегда под рукой.
Недостатки: Если строк станет много (десятки тысяч), форма начнет "тормозить" при каждом клике, так как эти данные будут передаваться на клиент и обратно при каждом серверном вызове. Временное хранилище лишено этого недостатка, так как на клиент передается только адрес (строка).

Резюме и рекомендации

Подведем итоги обсуждения и выберем оптимальную стратегию.

Почему нельзя передать менеджер?
Потому что временные таблицы живут только в рамках одного соединения с СУБД, а между вызовами 1С соединение разрывается.

Что делать?
Использовать паттерн "Кэширование результата":

  1. На первом шаге получить итоговые данные для записи.
  2. Выгрузить их в ТаблицаЗначений.
  3. Поместить эту таблицу во ВременноеХранилище, привязав к UUID формы.
  4. Сохранить адрес хранилища в строковый реквизит формы.
  5. На втором шаге прочитать таблицу по адресу и загрузить её параметром в новый запрос.

Это решение является стандартом для разработки на платформе 1С:Предприятие 8 и обеспечивает лучший баланс между надежностью и производительностью.

← На главную