Как сохранить выбранные значения в поле ввода со списком значений в 1С

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

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

Почему список значений не сохраняется сам по себе:

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

Проанализируем основные надежные способы решения этой задачи.

Способ 1. Синхронизация поля ввода с табличной частью справочника (рекомендуемый)

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

Разберем по шагам реализацию данного способа:

  1. В дереве метаданных у справочника создадим табличную часть (например, с именем ВыбранныеЭлементы).
  2. В табличной части создадим реквизит ЗначениеСписка с требуемым ссылочным типом данных.
  3. На форме оставим поле ввода, связанное с реквизитом формы СписокЗначенийПоля (тип СписокЗначений). Саму табличную часть отображать пользователю необязательно.
  4. При открытии формы загрузим строки табличной части в список значений:

Процедура ПриОткрытии()
    СписокЗначенийПоля.ЗагрузитьЗначения(ЭтотОбъект.ВыбранныеЭлементы.ВыгрузитьКолонку("ЗначениеСписка"));
КонецПроцедуры

Перед записью объекта выгрузим данные из списка значений обратно в строки табличной части:


Процедура ПередЗаписью(Отказ)
    ЭтотОбъект.ВыбранныеЭлементы.Очистить();
    Для Каждого ЭлементСписка Из СписокЗначенийПоля Цикл
        НоваяСтрока = ЭтотОбъект.ВыбранныеЭлементы.Добавить();
        НоваяСтрока.ЗначениеСписка = ЭлементСписка.Значение;
    КонецЦикла;
КонецПроцедуры

Способ 2. Использование реквизита с типом ХранилищеЗначения

Если структура табличной части избыточна и по выбранным значениям не требуется строить отчеты или выполнять поиск через язык запросов, можно сохранить весь объект СписокЗначений целиком в бинарном виде.

Рассмотрим порядок действий:

  1. В метаданных справочника добавим реквизит ХранилищеСписка с типом ХранилищеЗначения.
  2. В обработчике чтения или открытия формы извлечем коллекцию из хранилища:

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

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


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

Важный нюанс: при удалении объектов, ссылки на которые хранятся внутри ХранилищеЗначения, контроль ссылочной целостности не сработает, и в списке могут появиться недействительные ссылки вида «Объект не найден».

Способ 3. Сериализация списка в строковый реквизит

Еще один простой вариант — преобразование списка значений в текстовую строку и запись в реквизит справочника с типом Строка (неограниченной длины). Это удобно для простых вспомогательных настроек.

Посмотрим на пример сериализации через встроенные функции платформы:


// Сохранение списка в строку перед записью
Процедура ПередЗаписью(Отказ)
    ЭтотОбъект.СтрокаСписка = ЗначениеВСтрокуВнутр(СписокЗначенийПоля);
КонецПроцедуры

// Восстановление списка из строки при открытии
Процедура ПриОткрытии()
    Если Не ПустаяСтрока(ЭтотОбъект.СтрокаСписка) Тогда
        СписокЗначенийПоля = ЗначениеИзСтрокиВнутр(ЭтотОбъект.СтрокаСписка);
    КонецЕсли;
КонецПроцедуры

Также вместо ЗначениеВСтрокуВнутр можно использовать механизмы сериализации в XML через СериализаторXDTO или функции ЗначениеВXML и ЗначениеИзXML.

Способ 4. Хранение связей в подчиненном регистре сведений

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

Разберем структуру регистра:

  1. Измерение 1: ОбъектСправочника (тип — ссылка на целевой справочник, ведущее).
  2. Измерение 2: Значение (ссылочный тип элементов списка).

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

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

← На главную