Как быстро сохранить и восстановить множество реквизитов формы в регистр сведений

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

При разработке обработок, сложных рабочих мест или отчетов часто возникает задача: при закрытии формы сохранить все введенные пользователем параметры, а при повторном открытии — автоматически восстановить их. Когда реквизитов на форме много, ручное перечисление каждой строки вида Запись.Реквизит = ЭтаФорма.Реквизит становится громоздким и неудобным при дальнейшем развитии решения. Разберем различные подходы к пакетному сохранению и считыванию данных, от штатных возможностей платформы 1С до оптимальных вариантов работы с регистром сведений.

Вариант 1. Использование процедуры ЗаполнитьЗначенияСвойств через структуру

Процедура ЗаполнитьЗначенияСвойств() предназначена для быстрого копирования совпадающих по именам свойств из одного объекта в другой. Однако напрямую использовать управляемую форму как объект-источник на сервере нельзя, поскольку контекст формы не выступает универсальной коллекцией значений. Чтобы обойти это ограничение, упакуем реквизиты формы в промежуточную Структуру или выгрузим их программно.

Рассмотрим, как динамически собрать значения реквизитов управляемой формы с помощью платформенного метода ПолучитьРеквизиты() и передать их в менеджер записи регистра сведений:


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

Для обратной загрузки параметров при открытии формы воспользуемся этой же процедурой, но уже в обратном направлении, передав прочитанную запись в реквизиты формы:


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

Обратите внимание: у процедуры ЗаполнитьЗначенияСвойств() есть третий параметр — ЗаполняемыеСвойства (список имен через запятую). Если имена реквизитов формы и измерений/ресурсов регистра частично пересекаются с системными свойствами, явно указывайте список сохраняемых полей, чтобы избежать непредвиденных перезаписей.

Вариант 2. Пакетная загрузка набора записей через Таблицу Значений

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

Разберем по шагам, как выгрузить реквизиты формы пакетом:

  1. Создаем таблицу значений с колонками, в точности повторяющими имена измерений и ресурсов регистра.
  2. Заполняем строки таблицы парами «Имя реквизита — Значение».
  3. Устанавливаем отбор набора записей по текущему контексту (например, пользователю), загружаем таблицу и выполняем запись.

&НаСервере
Процедура СохранитьНастройкиПакетом()
    
    // Формируем таблицу под структуру регистра
    ТЗНастроек = Новый ТаблицаЗначений;
    ТЗНастроек.Колонки.Добавить("Пользователь");
    ТЗНастроек.Колонки.Добавить("КлючНастройки");
    ТЗНастроек.Колонки.Добавить("ЗначениеНастройки");
    
    МассивРеквизитов = ПолучитьРеквизиты();
    Для Каждого Реквизит Из МассивРеквизитов Цикл
        Если Реквизит.Имя <> "Объект" Тогда
            НоваяСтрока = ТЗНастроек.Добавить();
            НоваяСтрока.Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
            НоваяСтрока.КлючНастройки = Реквизит.Имя;
            НоваяСтрока.ЗначениеНастройки = ЭтотОбъект[Реквизит.Имя];
        КонецЕсли;
    КонецЦикла;
    
    // Записываем через набор записей
    Набор = РегистрыСведений.ПараметрыФорм.СоздатьНаборЗаписей();
    Набор.Отбор.Пользователь.Установить(ПользователиИнформационнойБазы.ТекущийПользователь());
    
    // Метод Загрузить заменяет строки набора содержимым таблицы
    Набор.Загрузить(ТЗНастроек);
    Набор.Записать(Истина);
    
КонецПроцедуры

Важный нюанс: вызов Набор.Записать(Истина) перезаписывает данные регистра в пределах установленного отбора. Если не наложить отбор по пользователю или объекту, будут очищены записи всех остальных пользователей информационной базы.

Вариант 3. Хранение настроек в ХранилищеЗначения

Если реквизитов на форме десятки или их состав часто модифицируется, создавать отдельное поле регистра под каждый реквизит нерационально. Оптимальный подход — упаковать все реквизиты формы в одну структуру и сохранить ее в единственный ресурс регистра с типом ХранилищеЗначения.

Посмотрим на пример упаковки и распаковки данных:


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

&НаСервере
Процедура ВосстановитьИзХранилища()
    
    МенеджерЗаписи = РегистрыСведений.ХранилищеНастроекФорм.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
    МенеджерЗаписи.ИмяФормы = ЭтаФорма.ИмяФормы;
    МенеджерЗаписи.Прочитать();
    
    Если МенеджерЗаписи.Выбран() Тогда
        СтруктураДанных = МенеджерЗаписи.Настройки.Получить();
        Если ТипЗнч(СтруктураДанных) = Тип("Структура") Тогда
            ЗаполнитьЗначенияСвойств(ЭтотОбъект, СтруктураДанных);
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Вариант 4. Штатные механизмы сохранения настроек без использования регистров

Создание собственного регистра сведений не всегда оправдано, так как платформа 1С предоставляет готовые механизмы для сохранения состояния форм:

  1. Автоматическое сохранение формы: в свойствах управляемой формы включите флаг СохранениеДанныхВНастройках (выбрав значение «Автоматически» или «Использовать»), а у нужных реквизитов формы установите признак Сохраняемые данные. В этом случае платформа берет на себя запись значений при закрытии формы и их загрузку при старте без единой строчки программного кода.
  2. Хранилище системных настроек: если требуется программный контроль над моментом сохранения и загрузки, воспользуйтесь системным объектом ХранилищеСистемныхНастроек:

// Сохранение настроек при закрытии формы
ХранилищеСистемныхНастроек.Сохранить("МояОбработка", "НастройкиФормы", СтруктураДанных);

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

Использование встроенного хранилища настроек или сериализации в ХранилищеЗначения избавляет от необходимости постоянно менять структуру метаданных при добавлении новых полей на форму.

← На главную