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