При разработке или доработке функционала в 1С, особенно при работе с проведением и отменой проведения документов, мы можем столкнуться с различными сложностями. Одна из таких проблем – ошибка «Попытка использования закрытого менеджера временных таблиц», которая возникает в процедуре обработки удаления проведения документа. Рассмотрим подробнее, почему возникает эта ошибка и как ее эффективно исправить.
Автор темы столкнулся с этой проблемой при отмене проведения документа, несмотря на то, что порядок действий, по его словам, был реализован аналогично типовым решениям 1С:Управление Торговлей (УТ). Суть ошибки заключается в том, что в какой-то момент система пытается обратиться к менеджеру временных таблиц, который уже был закрыт или недоступен.
Прежде чем углубляться в решение проблемы, давайте выясним, что представляет собой МенеджерВременныхТаблиц в 1С и каков его жизненный цикл.
Менеджер временных таблиц (МВТ) – это специальный объект платформы 1С, который позволяет создавать и управлять временными таблицами в контексте выполнения запросов. Временные таблицы используются для хранения промежуточных результатов запросов, что значительно повышает производительность и стабильность сложных запросов, особенно при работе с большими объемами данных.
МенеджерВременныхТаблиц обычно создается с помощью конструкции Новый МенеджерВременныхТаблиц(). В типовых конфигурациях при вызове стандартных методов Провести() или ОтменитьПроведение() менеджер временных таблиц может создаваться автоматически платформой в рамках транзакции проведения.
ПОМЕСТИТЬ. Он действует на протяжении выполнения запросов, которым был передан.
Закрыть() не требуется. Он уничтожается автоматически, когда соответствующая переменная выходит из области видимости, например, при выходе из процедуры, в которой был создан.
Ошибка "Попытка использования закрытого менеджера временных таблиц" возникает, когда наш код пытается выполнить операцию с временными таблицами, но МВТ, к которому идет обращение, уже закрыт или не инициализирован в текущем контексте. Разберем основные причины:
ОтменаПроведения происходит вне контекста активного менеджера временных таблиц (например, в обработчике ПередЗаписью или в других местах, не предназначенных для таких операций в рамках процедуры проведения), то возникает данная ошибка.
ОбработкаУдаленияПроведения), а МВТ уже был неявно закрыт платформой, возникает конфликт. Платформа могла уже закрыть свой МВТ после выполнения своих операций, а наш код все еще ожидает его наличия.
ПередЗаписью или других обработчиках могут также привести к тому, что менеджер временных таблиц будет создан и закрыт несколько раз, что нарушит его жизненный цикл.
Давайте рассмотрим код, представленный автором темы:
Процедура ОбработкаУдаленияПроведения(Отказ)
нПроведениеСерверУТ.ИнициализироватьДополнительныеСвойстваДляПроведения(Ссылка, ДополнительныеСвойства);
нПроведениеСерверУТ.ПодготовитьНаборыЗаписейКРегистрацииДвижений(ЭтотОбъект);
СформироватьСписокРегистровДляКонтроля();
нПроведениеСерверУТ.ЗаписатьНаборыЗаписей(ЭтотОбъект);
нПроведениеСерверУТ.ОчиститьДополнительныеСвойстваДляПроведения(ДополнительныеСвойства);
КонецПроцедуры
В этом коде мы видим, что отмена проведения осуществляется через серверные процедуры, которые, по всей видимости, используют временные таблицы для формирования движений. Ошибка возникает в момент, когда одна из этих процедур (вероятно, внутри нПроведениеСерверУТ.ЗаписатьНаборыЗаписей) пытается обратиться к менеджеру временных таблиц.
В качестве быстрого, но не всегда корректного решения, на форуме было предложено пересоздавать менеджер временных таблиц перед использованием:
ДополнительныеСвойства.ДляПроведения.СтруктураВременныеТаблицы.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц
Мы помещаем эту строку кода перед вызовом процедуры, которая вызывает ошибку. Например, это может быть перед нПроведениеСерверУТ.ЗаписатьНаборыЗаписей(ЭтотОбъект);
Почему это "костыль"? Мы должны понимать, что это решение является "костылем", потому что оно не устраняет первопричину проблемы. Если менеджер временных таблиц был закрыт, это означает, что система уже завершила свою работу с ним или ожидает другого менеджера. Принудительное создание нового менеджера может привести к нарушению логики работы, некорректному поведению в других частях системы или утечкам памяти, если старый менеджер не был корректно очищен. Оно "затыкает" проблему в одном месте, но не решает системный конфликт.
Ключевой момент в решении этой проблемы – это настройка документа "удалять движ автоматически". Автор темы сам пришел к этому выводу в конце обсуждения. Давайте разберем этот аспект подробнее.
Если для нашего документа установлена настройка "удалять движ автоматически", это означает, что платформа 1С самостоятельно управляет удалением движений регистров при отмене проведения. В этом случае, при вызове метода ОтменитьПроведение(), платформа сама создает и управляет своим менеджером временных таблиц, выполняет все необходимые операции по удалению движений и затем закрывает МВТ. Наш код в ОбработкаУдаленияПроведения в этом сценарии не должен пытаться выполнять операции, которые требуют активного МВТ, так как он уже мог быть закрыт платформой. Если нам необходимо выполнить какую-то логику, связанную с временными таблицами, то она должна быть в контексте, где МВТ гарантированно активен, или же мы должны использовать свой собственный МВТ, явно передавая его. Однако, при автоматическом удалении движений, ОбработкаУдаленияПроведения часто не должна содержать сложную логику, связанную с записями регистров.
Это наиболее вероятный сценарий для возникновения описываемой проблемы и путь к ее корректному решению. Если эта настройка отключена, мы берем на себя ответственность за удаление движений документа в процедуре ОбработкаУдаленияПроведения. Именно так поступают в типовых конфигурациях 1С для сложных документов. В этом случае мы должны явно управлять менеджером временных таблиц.
Примерный подход для ручного управления удалением движений:
Новый МенеджерВременныхТаблиц() в начале нашей процедуры обработки.
ОбработкаУдаленияПроведения или в вызываемых из нее серверных процедурах мы реализуем логику по очистке движений. Это может быть либо полный откат движений по регистрам, либо формирование обратных движений.
Рассмотрим, как могла бы выглядеть процедура ОбработкаУдаленияПроведения с учетом явной передачи менеджера временных таблиц:
Процедура ОбработкаУдаленияПроведения(Отказ)
// Создаем новый менеджер временных таблиц, если он еще не передан
// или если наш код должен работать независимо от платформенного МВТ.
// В большинстве случаев при ручном управлении движениями мы сами создаем МВТ.
Если Не ДополнительныеСвойства.ДляПроведения.СтруктураВременныеТаблицы.Свойство("МенеджерВременныхТаблиц") Тогда
ДополнительныеСвойства.ДляПроведения.СтруктураВременныеТаблицы.Вставить("МенеджерВременныхТаблиц", Новый МенеджерВременныхТаблиц());
КонецЕсли;
// Передаем ДополнительныеСвойства, в которых теперь находится наш МВТ
нПроведениеСерверУТ.ИнициализироватьДополнительныеСвойстваДляПроведения(Ссылка, ДополнительныеСвойства);
// Подготовка и запись движений, которые будут удалены или сформированы как обратные.
// Эти процедуры должны использовать МВТ из ДополнительныеСвойства
нПроведениеСерверУТ.ПодготовитьНаборыЗаписейКРегистрацииДвижений(ЭтотОбъект);
СформироватьСписокРегистровДляКонтроля();
нПроведениеСерверУТ.ЗаписатьНаборыЗаписей(ЭтотОбъект); // Здесь происходит работа с МВТ
нПроведениеСерверУТ.ОчиститьДополнительныеСвойстваДляПроведения(ДополнительныеСвойства);
// Явное закрытие МВТ не требуется, он закроется при выходе переменной из области видимости,
// но в некоторых случаях может быть полезно для освобождения ресурсов.
// Если МВТ хранится в ДополнительныеСвойства, он будет существовать пока ДополнительныеСвойства доступны.
// Однако при завершении процедуры ДополнительныеСвойства уничтожаются, и МВТ тоже.
КонецПроцедуры
Важно: убедитесь, что все функции и процедуры, такие как нПроведениеСерверУТ.ИнициализироватьДополнительныеСвойстваДляПроведения, нПроведениеСерверУТ.ПодготовитьНаборыЗаписейКРегистрацииДвижений и нПроведениеСерверУТ.ЗаписатьНаборыЗаписей, корректно принимают и используют переданный МенеджерВременныхТаблиц из структуры ДополнительныеСвойства.
Чтобы избежать подобных ошибок и повысить производительность, мы рекомендуем следовать следующим правилам при работе с временными таблицами:
Следуя этим рекомендациям и правильно управляя жизненным циклом менеджера временных таблиц, мы сможем эффективно решать проблемы, связанные с ошибкой "Попытка использования закрытого менеджера временных таблиц", и обеспечивать стабильную работу наших конфигураций 1С.