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