При переходе с платформы 1С:Предприятие 8.2 на версию 8.3 программисты часто сталкиваются с неприятным сюрпризом: код, который годами работал исправно, внезапно начинает выдавать ошибку: "Переданное значение не может быть помещено во временное хранилище". Чаще всего это происходит при попытке сохранить данные табличной части или целого объекта (документа, справочника) непосредственно из управляемой формы. В этой статье мы подробно разберем, почему платформа стала более требовательной, и как правильно адаптировать ваш код под новые реалии.
Разберем ситуацию, которая произошла у автора темы. В версии 8.2 вы могли написать ПоместитьВоВременноеХранилище(Объект.Оплата), где Объект.Оплата — это табличная часть, и система "проглатывала" это. В версии 8.3 такой фокус больше не проходит. Почему?
Основная причина кроется в глубокой переработке механизмов отказоустойчивости кластера 1С. В современных версиях 8.3 реализована возможность передачи сеансовых данных между рабочими процессами. Если один процесс аварийно завершается, сеанс пользователя должен "переехать" на другой процесс без потери данных. Чтобы это реализовать, абсолютно все данные, находящиеся во временном хранилище, должны уметь превращаться в последовательность байтов (сериализоваться), чтобы их можно было передать по сети или сохранить на диск.
Проблема в том, что типы данных, с которыми мы работаем на форме (например, ДанныеФормыКоллекция, ДанныеФормыСтруктура), а также серверные объекты (ДокументОбъект, СправочникОбъект), содержат в себе не только чистые данные, но и контекст соединения, ссылки на внутренние менеджеры платформы и указатели памяти. Эти "живые" связи невозможно сериализовать и восстановить на другом сервере. Поэтому платформа 8.3 блокирует попытку поместить такие объекты в хранилище еще на этапе вызова метода.
Прежде чем приступать к исправлению, давайте проанализируем, какие типы данных являются "безопасными", а какие вызовут ошибку. Для этого полезно заглядывать в синтакс-помощник и проверять свойство "Сериализуется" в разделе описания типа.
ДокументОбъект в Массив, а массив попытаетесь поместить в хранилище — вы получите ошибку.Если ваша задача — сохранить данные табличной части, которую пользователь видит на экране, самым простым и эффективным решением будет преобразование ее в обычную Таблицу Значений. Рассмотрим, как это сделать правильно.
Вместо ошибочного кода:
// Ошибка в 8.3: Объект.Оплата имеет тип ДанныеФормыКоллекция
Адрес = ПоместитьВоВременноеХранилище(Объект.Оплата, ЭтаФорма.УникальныйИдентификатор);
Используйте выгрузку в универсальную коллекцию:
// Правильно: выгружаем данные в сериализуемую ТаблицуЗначений
ТаблицаДляХранения = Объект.Оплата.Выгрузить();
Адрес = ПоместитьВоВременноеХранилище(ТаблицаДляХранения, ЭтаФорма.УникальныйИдентификатор);
В этом случае платформа создаст копию данных в виде ТаблицыЗначений, которая не привязана к контексту формы и может быть легко сохранена в байтовом виде.
Бывают ситуации, когда вам нужно поместить в хранилище не просто таблицу, а весь объект целиком (например, для передачи в фоновое задание). В этом случае мы должны использовать стандартные механизмы преобразования управляемых форм.
Рассмотрим по шагам, как подготовить объект к помещению в хранилище:
Структуру или выгружаем все ТЧ в Таблицы Значений.Пример кода на сервере:
&НаСервере
Процедура СохранитьОбъектВХранилище()
// 1. Получаем объект из данных формы
ТекОбъект = ДанныеФормыВЗначение(Объект, Тип("ДокументОбъект.ОплатаПоставщику"));
// 2. Поскольку ДокументОбъект сам не сериализуется,
// создаем структуру для хранения его реквизитов
ДанныеДляСохранения = Новый Структура;
ДанныеДляСохранения.Вставить("Дата", ТекОбъект.Дата);
ДанныеДляСохранения.Вставить("Контрагент", ТекОбъект.Контрагент);
ДанныеДляСохранения.Вставить("ТабличнаяЧасть", ТекОбъект.Оплата.Выгрузить());
// 3. Теперь данные можно безопасно поместить в хранилище
АдресХранилища = ПоместитьВоВременноеХранилище(ДанныеДляСохранения, ЭтаФорма.УникальныйИдентификатор);
КонецПроцедуры
Интересный нюанс упомянул один из участников обсуждения: некоторые объекты, такие как элементы отбора компоновки данных, могут вести себя по-разному. Однако общее правило остается прежним: если вы сталкиваетесь с ошибкой, попробуйте "обернуть" данные. Для сложных настроек (например, НастройкиКомпоновкиДанных) рекомендуется использовать метод СериализаторXDTO.ЗаписатьXDTO(), чтобы превратить объект в строку XML, и помещать в хранилище уже строку.
Важно понимать, почему проблема может возникнуть внезапно при обновлении конфигурации. Если в вашей базе установлен "Режим совместимости" со старыми версиями (например, 8.2.16), платформа может позволять помещать несериализуемые объекты во временное хранилище ради обратной совместимости. Однако, как только вы отключаете режим совместимости или устанавливаете его в значение "8.3.х", включается строгий контроль.
Проанализируем последствия: отказ от совместимости — это не "ухудшение возможностей", как считает автор вопроса, а шаг к стабильности. Несериализуемые объекты в хранилище часто становились причиной утечек памяти на сервере 1С, так как они удерживали ссылки на тяжелые контексты, которые сборщик мусора не мог очистить вовремя.
Проанализируем ситуацию с производительностью. Автор сообщения переживал, что выгрузка в таблицу значений замедлит работу из-за медленного интернета. На самом деле, ситуация обратная:
ТаблицаЗначений содержит только данные. Она компактна при передаче.ДанныеФормыКоллекция — это сложный объект-посредник. Передача его "как есть" (если бы это было возможно) требовала бы гораздо большего оверхеда на поддержку синхронизации состояний.Поэтому использование Выгрузить() — это не просто способ избежать ошибки, но и более правильный с точки зрения архитектуры способ работы с памятью сервера.
Подведем итог: Если вы столкнулись с ошибкой помещения во временное хранилище в 1С 8.3, проверьте тип передаваемого значения. Если это объект формы или табличная часть — выгружайте их в ТаблицуЗначений или Структуру. Это гарантирует стабильную работу вашего решения в распределенной среде кластера 1С и отсутствие проблем при будущих обновлениях платформы.