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