Почему после записи документа в 1С очищаются реквизиты формы, не связанные с данными?

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

Часто при работе с управляемыми формами в 1С мы сталкиваемся с ситуацией: мы добавили на форму реквизиты, которые не хранятся в базе данных, а рассчитываются динамически. Пользователь видит нужные цифры, нажимает кнопку "Записать", и... эти поля становятся пустыми. Давайте вместе разберемся, почему так происходит и какие существуют способы решить эту задачу.

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

Решение 1: Пересчет данных при каждом открытии и после записи

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

Разберем по шагам, как это реализовать:

  1. Создадим на сервере специальную процедуру, которая будет выполнять все необходимые вычисления и заполнять наши реквизиты формы. Это помогает избежать дублирования кода, подобно тому как мы оптимизируем связанные табличные части для удобства работы.
  2. Будем вызывать эту процедуру из двух ключевых серверных обработчиков событий формы:
    • ПриСозданииНаСервере — сработает один раз, когда форма только открывается.
    • ПослеЗаписиНаСервере — сработает каждый раз после успешной записи объекта (если вам нужна абсолютная надежность транзакции, рассмотрите самодельный обработчик ПослеЗаписи).

Посмотрим на пример: допустим, у нас есть документ "Заказ", а на форме мы хотим видеть расчетное поле ПроцентВыполненияЗаказа, которое не хранится в документе.


&НаСервере
Процедура РассчитатьДополнительныеРеквизиты()
    // Здесь ваша сложная логика расчета
    // Например, получаем данные из других регистров по этому заказу
    Объект.ПроцентВыполненияЗаказа = РассчитатьПроцентВыполнения(Объект.Ссылка);
КонецПроцедуры

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    РассчитатьДополнительныеРеквизиты();
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
    РассчитатьДополнительныеРеквизиты();
КонецПроцедуры

Этот метод отлично подходит для несложных расчетов, которые не сильно влияют на производительность. Для большинства повседневных задач его более чем достаточно.

Решение 2: Хранение данных в базе данных

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

1. Добавление реквизитов в сам объект.

Это самый надежный способ. Мы просто добавляем новый реквизит (например, ПроцентВыполненияЗаказа) в сам объект конфигурации (документ "Заказ"). Расчет этого реквизита можно производить в серверном обработчике ПередЗаписьюНаСервере. Таким образом, данные будут записаны вместе с документом и всегда будут доступны.


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    ТекущийОбъект.ПроцентВыполненияЗаказа = РассчитатьПроцентВыполнения(ТекущийОбъект.Ссылка);
КонецПроцедуры

2. Использование отдельного регистра сведений.

Иногда не хочется "засорять" основной объект вспомогательными данными. В этом случае можно создать отдельный, подчиненный документу РегистрСведений. Этот подход особенно удобен при работе с расширениями, так как позволяет добавить хранилище для наших данных, не изменяя основную конфигурацию. А для просмотра этих записей в интерфейсе можно эффективно использовать отборы динамического списка.

Решение 3: Использование временного хранилища

Этот способ позволяет "перенести" наши расчетные данные через процедуру записи. Механизм работает так: перед записью мы сохраняем данные в специальное временное хранилище на сервере, а после записи — забираем их оттуда и снова помещаем на форму. Технически это напоминает поиск решения, как передать Таблицу Значений в Динамический Список, когда стандартные методы не подходят.

Разберем по шагам:

  1. В обработчике ПередЗаписьюНаСервере мы помещаем значение нашего реквизита во временное хранилище с помощью функции ПоместитьВоВременноеХранилище(). Эта функция возвращает уникальный адрес, который мы сохраняем в переменную.
  2. В обработчике ПослеЗаписиНаСервере мы используем этот адрес и функцию ПолучитьИзВременногоХранилища(), чтобы получить наши данные обратно и присвоить их реквизиту формы.

Посмотрим на пример кода:


&НаСервере
Перем АдресВременногоХранилища;

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // Помещаем значение нашего реквизита формы во временное хранилище
    АдресВременногоХранилища = ПоместитьВоВременноеХранилище(Объект.ПроцентВыполненияЗаказа, УникальныйИдентификатор);
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
    // Получаем данные из хранилища и снова устанавливаем в реквизит
    ДанныеИзХранилища = ПолучитьИзВременногоХранилища(АдресВременногоХранилища);
    Если ДанныеИзХранилища <> Неопределено Тогда
        Объект.ПроцентВыполненияЗаказа = ДанныеИзХранилища;
    КонецЕсли;
КонецПроцедуры

Этот метод элегантен и не требует изменения структуры базы данных, идеально подходя для данных, которые нужны только в рамках текущей сессии работы с формой.

Решение 4: Кэширование данных на время сеанса

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

Платформа 1С предоставляет отличный механизм: общие модули с повторным использованием возвращаемых значений. Для этого нужно:

  1. Создать общий серверный модуль.
  2. В его свойствах установить флаг "Повторное использование возвращаемых значений" в положение "На время сеанса".
  3. Разместить в этом модуле экспортную функцию для наших расчетов.

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

Пример функции в таком модуле:


// Общий модуль "РасчетныеФункцииСерверКэшируемый"
Функция РассчитатьСложныйПоказатель(Параметр1, Параметр2) Экспорт
    
    // ... здесь очень долгие и сложные вычисления ...
    Результат = ...; 
    Возврат Результат;

КонецФункции

Этот подход значительно ускоряет работу формы при многократных обращениях к одним и тем же расчетным данным.

← На главную