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