При разработке в современных конфигурациях на базе 1С:ERP (таких как УТ 11, КА 2 или сама ERP 2), программисты часто сталкиваются со специфической ошибкой: «Попытка использования закрытого менеджера временных таблиц». Эта проблема обычно возникает в модулях набора записей регистров накопления или при программном проведении документов из внешних обработок. В этой статье мы подробно разберем природу этой ошибки и рассмотрим все эффективные способы её решения.
Для начала разберем, что такое МенеджерВременныхТаблиц (МВТ). Это объект платформы, который позволяет хранить временные таблицы между выполнениями разных запросов в рамках одного сеанса. В универсальном механизме проведения типовых решений 1С, МВТ создается в начале транзакции и передается через структуру ДополнительныеСвойства документа.
Ошибка «Попытка использования закрытого менеджера...» означает, что объект МВТ все еще существует в памяти, но для него уже был вызван метод Закрыть(). После закрытия менеджера любые попытки выполнить запрос, привязанный к нему, приводят к фатальному завершению операции. Рассмотрим основные сценарии, когда это происходит:
ОбработкаПроведения вызываются сервисные методы, которые «подчищают» за собой ресурсы, включая закрытие МВТ.Записать(РежимЗаписиДокумента.Проведение), то при втором проходе система попытается использовать МВТ, оставшийся в ДополнительныеСвойства от первого прохода, но он уже будет закрыт.Рассмотрим подробнее каждое решение, предложенное сообществом и проверенное практикой.
Если вы дописываете логику формирования движений непосредственно в процедуру ОбработкаПроведения модуля объекта, критически важно, где именно расположен ваш код. Проанализируем типовую структуру этой процедуры:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// 1. Инициализация данных для проведения
// ... здесь подготавливаются таблицы значений ...
// 2. ВАШ КОД ДОЛЖЕН БЫТЬ ЗДЕСЬ
// Формируйте движения по своим регистрам ДО финальных процедур
Движения.РасчетыСПоставщиками.Записывать = Истина;
НоваяСтрока = Движения.РасчетыСПоставщиками.Добавить();
// ... заполнение свойств движения ...
// 3. Типовой блок завершения (ФИНАЛИЗАЦИЯ)
ПроведениеСервер.ЗаписатьНаборыЗаписей(ЭтотОбъект);
ПроведениеСервер.ВыполнитьКонтрольРезультатовПроведения(ЭтотОбъект, Отказ);
// ВНИМАНИЕ: После этой строки менеджер временных таблиц может быть закрыт!
ПроведениеСервер.ОчиститьДополнительныеСвойстваДляПроведения(ДополнительныеСвойства);
КонецПроцедуры
Важный вывод: Если вы поместите свой код после вызова ОчиститьДополнительныеСвойстваДляПроведения, вы гарантированно получите ошибку, так как ресурсы проведения уже освобождены. Всегда вставляйте кастомные движения до начала типовой фиксации записей.
Выясним причину ошибки при работе с внешними обработками. Часто разработчики пишут код следующим образом:
// ОШИБОЧНЫЙ ВАРиАНТ
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение); // Первое проведение
// Что-то меняем в объекте
ДокОбъект.Комментарий = "Изменено программно";
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение); // ОШИБКА ЗДЕСЬ!
Почему возникает ошибка? При первом вызове Записать() структура ДополнительныеСвойства объекта заполняется служебными данными проведения. По завершении процесса менеджер временных таблиц закрывается, но ссылка на него остается в свойстве ДокОбъект.ДополнительныеСвойства.ДляПроведения. При втором вызове система видит готовую структуру и пытается использовать старый, закрытый менеджер.
Чтобы избежать этого, разберем правильный подход — переполучение объекта:
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
// Для повторного проведения ОБЯЗАТЕЛЬНО получаем объект заново
ДокОбъект = ДокОбъект.Ссылка.ПолучитьОбъект();
ДокОбъект.Статус = Перечисления.Статусы.Выполнено;
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение); // Теперь ошибки не будет
При вызове ПолучитьОбъект() создается чистый экземпляр в оперативной памяти, его ДополнительныеСвойства пусты, и механизм проведения инициализирует новый рабочий МВТ.
Если по каким-то причинам (например, из соображений производительности) вы не хотите перечитывать объект из базы данных через ПолучитьОбъект(), можно воспользоваться методом ручной очистки свойств. Рассмотрим, как это реализовать:
Перед повторным вызовом метода Записать(), выполните команду:
ОбъектДокумента.ДополнительныеСвойства.Удалить("ДляПроведения");
ОбъектДокумента.Записать(РежимЗаписиДокумента.Проведение);
Это «обманет» типовые механизмы, заставив их думать, что документ проводится в первый раз в текущем контексте, и структура ресурсов будет создана с нуля.
Проанализируем ситуацию, когда ошибка возникает в модуле набора записей регистра. Платформа 1С при записи набора пытается вычислить разницу между старыми и новыми записями для оптимизации итогов. Для этого ей нужен МВТ.
Если ваша задача позволяет, вы можете отключить этот расчет. Это снимет потребность в менеджере временных таблиц для конкретного набора записей:
Движения.РасчетыСКлиентами.ДополнительныеСвойства.Вставить("РассчитыватьИзменения", Ложь);
Обратите внимание: Этот метод следует использовать с осторожностью, так как он может повлиять на производительность при обновлении итогов, если в наборе записей очень много строк. Однако для небольших движений это отличная «заплатка», не требующая глубокого вмешательства в логику.
В некоторых случаях, особенно в нетиповых документах или при сложной интеграции, помогает прямая инициализация нового объекта МВТ в структуре проведения. Рассмотрим пример кода, который можно вставить в начало процедуры проведения или в подписку:
Если ЭтотОбъект.ДополнительныеСвойства.ДляПроведения.СтруктураВременныеТаблицы.МенеджерВременныхТаблиц.Закрыт() Тогда
ЭтотОбъект.ДополнительныеСвойства.ДляПроведения.СтруктураВременныеТаблицы.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
КонецЕсли;
Хотя этот метод кажется простым, мы рекомендуем использовать его только в крайнем случае, когда методы с ПолучитьОбъект() или правильным порядком вызовов недоступны.
Подведем итог нашему анализу. Ошибка закрытого менеджера — это не баг платформы, а следствие работы механизмов оптимизации ресурсов в современных конфигурациях. Для эффективного решения задачи придерживайтесь следующих правил:
ОбработкаПроведения.Ссылка.ПолучитьОбъект().РассчитыватьИзменения = Ложь в ДополнительныеСвойства набора записей.ПроведениеСервер.Соблюдение этих архитектурных принципов позволит вам создавать стабильный код и избегать трудноуловимых ошибок при проведении документов в среде 1С:Предприятие 8.3.