Как сохранить список значений в реквизите справочника 1С

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

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

Почему СписокЗначений не сохраняется в базе данных?

Объект СписокЗначений предназначен в первую очередь для интерактивной работы пользователя: выбора элементов, отметки флажками или визуального отображения списка. Он существует только в оперативной памяти. Когда мы пытаемся назначить его реквизиту справочника, система сталкивается с тем, что в структуре SQL-таблицы нет подходящего формата для хранения этого сложного объекта. Для решения проблемы нам необходимо либо изменить структуру хранения данных, либо преобразовать объект в формат, который база данных сможет «переварить».

Способ 1. Использование табличной части объекта

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

Преимущества этого метода:

  1. Возможность построения запросов по вложенным данным (например, найти все договоры, где указан конкретный пользователь).
  2. Простота вывода на форму через стандартный элемент «Таблица».
  3. Автоматический контроль ссылочной целостности (система не даст удалить пользователя, если он указан в табличной части договора).

Разберем реализацию: в метаданных справочника ДоговорыКонтрагентов создаем табличную часть (например, ОтветственныеЛица) и добавляем в нее реквизит Пользователь с типом СправочникСсылка.Пользователи. Теперь данные будут надежно храниться в подчиненной таблице базы данных.

Способ 2. ХранилищеЗначений — бинарное сохранение

Если по каким-то причинам использование табличной части нежелательно (например, данных слишком много или структура списка постоянно меняется), можно использовать реквизит с типом ХранилищеЗначений. Этот тип позволяет упаковать любой объект 1С (включая массив или список значений) в бинарный формат.

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

Проанализируем код сохранения в событии ПередЗаписьюНаСервере:


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

И код восстановления данных при открытии в событии ПриЧтенииНаСервере:


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

Важное ограничение: данные внутри ХранилищаЗначений невозможно использовать в условиях запросов ГДЕ. Этот способ подходит только для отображения информации внутри карточки объекта.

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

Выясним причину популярности этого метода в современных конфигурациях. Если создать реквизит типа Строка (неограниченной длины), в него можно записывать данные в формате JSON. Это похоже на метод с хранилищем, но данные остаются в человекочитаемом виде.

Рассмотрим, как реализовать преобразование списка в JSON:


// Сериализация списка в строку
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СписокПользователей.ВыгрузитьЗначения());
СтрокаДляХранения = ЗаписьJSON.Закрыть();

// Десериализация из строки обратно в список
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаДляХранения);
МассивРезультат = ПрочитатьJSON(ЧтениеJSON);
СписокПользователей.ЗагрузитьЗначения(МассивРезультат);

Этот способ удобен при интеграции с веб-сервисами или внешними системами, однако он также не позволяет делать эффективные отборы в динамических списках.

Способ 4. Использование независимого регистра сведений

Проанализируем ситуацию, когда нам нужно хранить список пользователей, не меняя структуру самого справочника ДоговорыКонтрагентов (например, если справочник находится на поддержке и закрыт для редактирования). В этом случае оптимальным решением станет создание нового РегистраСведений.

Настроим структуру регистра:

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

Резюме и рекомендации

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

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

← На главную