При разработке расширений в среде 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда данные, помещенные во временное хранилище в основной конфигурации, оказываются недоступны в методах-обработчиках расширения (например, с аннотацией &После). Рассмотрим типичный сценарий на примере типовой конфигурации «Управление торговлей 11.4» и обработки «Обеспечение потребностей», выясним причины такого поведения платформы и разберем корректные способы решения задачи.
Рассмотрим ситуацию. В модуле менеджера существует процедура ТаблицаПотребностейПоЗаказамИОстатков(Параметры, АдресРезультата). В самом конце выполнения этой процедуры выполняется помещение подготовленной таблицы во временное хранилище:
ПоместитьВоВременноеХранилище(Таблица, АдресРезультата);
КонецПроцедуры
Разработчик создает расширение и хочет программно изменить эту таблицу сразу после того, как она была сформирована, используя аннотацию &После. Однако при попытке вызвать ПолучитьИзВременногоХранилища(АдресРезультата) функция возвращает Неопределено. Проанализируем, почему это происходит.
Основная причина кроется в жизненном цикле данных во временном хранилище и стандартах разработки 1С. В типовых конфигурациях (таких как УТ 11, ERP, КА) часто используется паттерн, при котором вызывающий код считывает данные из хранилища сразу после завершения процедуры. В 1С существует параметр функции ПолучитьИзВременногоХранилища(Адрес, УдалятьИзХранилища). Если второй параметр установлен в значение Истина, данные удаляются из хранилища мгновенно после прочтения.
Когда мы используем аннотацию &После, наш код выполняется формально после завершения основной процедуры, но в рамках того же серверного вызова. Однако если управление возвращается в вызывающий метод, который инициировал расчет, он может успеть считать и удалить данные до того, как расширение обратится к ним, или же механизмы платформы по завершении контекста процедуры производят очистку, если не передан УникальныйИдентификаторФормы.
Посмотрим на то, как обычно инициализируется адрес для результата в обработке «Обеспечение потребностей»:
ПараметрыВыполнения.АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, ПараметрыВыполнения.ИдентификаторФормы);
Важный момент: если при создании адреса был передан ИдентификаторФормы, данные должны храниться до закрытия этой формы. Однако в сложных обработках расчет часто уходит в фоновое задание. Данные, помещенные в хранилище внутри фонового задания, ведут себя специфически: они доступны основному сеансу только после завершения задания и только в течение очень короткого промежутка времени, необходимого для их получения.
Выясним причину странного эффекта, который разработчики называют «волшебством»: в отладчике при пошаговом выполнении данные иногда удается получить, а в обычном режиме — нет. Это связано с тем, что отладчик удерживает контекст сеанса и временные объекты дольше, чем это делает система в автоматическом режиме. При «быстром» исполнении срабатывают механизмы оптимизации памяти 1С, и объект удаляется сразу, как только на него пропадают ссылки в основном коде.
Проанализируем наиболее надежный способ перехвата данных — использование аннотации &Вместо. Этот метод позволяет нам полностью контролировать момент получения данных из хранилища. Вместо того чтобы ждать завершения оригинальной процедуры, мы подменяем её вызов.
Рассмотрим пример реализации:
&Вместо("ТаблицаПотребностейПоЗаказамИОстатков")
Процедура О_ТаблицаПотребностейПоЗаказамИОстатков(Параметры, АдресРезультата)
// Вызываем оригинальную логику через ПродолжитьВызов
ПродолжитьВызов(Параметры, АдресРезультата);
// Сразу после выполнения основной части получаем данные
Таблица = ПолучитьИзВременногоХранилища(АдресРезультата);
Если ТипЗнч(Таблица) = Тип("ТаблицаЗначений") Тогда
// Выполняем модификацию таблицы
// Например: ДобавитьСвоюКолонку(Таблица);
// Помещаем измененную таблицу обратно по тому же адресу
ПоместитьВоВременноеХранилище(Таблица, АдресРезультата);
КонецЕсли;
КонецПроцедуры
Почему это работает: Мы находимся в контексте выполнения той же самой процедуры, управление еще не вернулось в вызывающий код, который может вызвать очистку хранилища. Мы гарантированно успеваем прочитать данные.
Если расширение модуля менеджера не дает стабильного результата из-за специфики работы фоновых заданий, проанализируем альтернативный путь. В обработках типа «Обеспечение потребностей» всегда есть клиентская часть (модуль формы), которая ожидает завершения расчета.
Найдем в модуле формы процедуру, которая вызывается после завершения серверного расчета (например, после завершения фонового задания). В типовых решениях это часто обработчики ожидания или процедуры типа ПослеЗавершенияРасчетаНаСервере. Если внедрить логику расширения там, данные можно будет получить по адресу хранилища, так как форма еще открыта и хранилище, привязанное к её УникальныйИдентификатор, будет валидно.
Выясним преимущества этого метода:
Подведем итог и сформулируем правила, которые помогут избежать подобных ошибок в будущем:
ПоместитьВоВременноеХранилище не передан второй параметр (UID формы), данные будут жить только до следующего серверного вызова.ПолучитьИзВременногоХранилища(Адрес, Истина) удаляет объект. Типовой код 1С почти всегда использует именно такой вызов.&Вместо с использованием ПродолжитьВызов() является наиболее стабильным инструментом в расширениях.Если Таблица <> Неопределено Тогда, прежде чем обращаться к методам объекта.Соблюдение этих правил и понимание механизмов очистки временного хранилища платформой 1С позволит вам создавать стабильные расширения, которые корректно работают даже в сложных многопоточных процессах типовых конфигураций.