Как реализовать хранение списка значений в измерении регистра сведений?

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

При проектировании метаданных в системе «1С:Предприятие» разработчики часто сталкиваются с ограничением: измерение регистра сведений должно быть атомарным. Это означает, что в одну ячейку (поле) нельзя напрямую поместить коллекцию, такую как СписокЗначений или Массив. Однако задачи, требующие сопоставления одного объекта целому набору других объектов, встречаются повсеместно. Рассмотрим подробнее, почему существует это ограничение и какими способами его можно элегантно обойти.

Почему нельзя хранить список напрямую в измерении?

Проанализируем техническую сторону вопроса. Измерения регистра сведений формируют уникальный ключ записи. На уровне СУБД (SQL Server, PostgreSQL и др.) по этим полям строится индекс. Динамические коллекции 1С являются объектами оперативной памяти и не имеют фиксированного типа данных, который можно было бы однозначно проиндексировать в базе данных. Поэтому платформа 1С строго ограничивает типы измерений ссылочными и примитивными типами.

Решение 1. Классическая нормализация данных (несколько записей)

Разберем самый правильный с точки зрения теории реляционных баз данных подход. Если нам нужно сопоставить «Подразделение-источник» списку из пяти «Подразделений-приемников», мы создаем пять отдельных записей в регистре.

В этом случае структура регистра выглядит следующим образом:

Если для одного источника назначено 10 приемников, в регистре будет 10 строк. Рассмотрим преимущества этого метода:

  1. Скорость поиска: Запросы к регистру будут работать максимально быстро, так как используются стандартные индексы.
  2. Использование виртуальных таблиц: Мы можем легко получить СрезПоследних или выполнить соединение в запросе по любому конкретному подразделению-приемнику.
  3. Гибкость: Мы можем легко добавлять или удалять связи, не переписывая массив целиком.

Решение 2. Создание справочника-контейнера

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

  1. Создадим новый объект метаданных — Справочник.НаборыПодразделений.
  2. Добавим в этот справочник табличную часть Состав с реквизитом Подразделение.
  3. В регистре сведений в качестве измерения укажем тип СправочникСсылка.НаборыПодразделений.

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

Решение 3. Сериализация списка в строку (JSON)

Выясним причину, по которой иногда выбирают хранение данных в текстовом виде. Если нам не требуется искать записи по конкретному элементу списка внутри запроса, а нужно лишь «прочитать и развернуть» список в коде 1С, можно использовать сериализацию.

Для этого изменим тип измерения на Строка (неограниченной длины или с запасом). Перед записью в регистр преобразуем наш массив в строку JSON:


// Пример записи списка в строку
МассивПриемников = Новый Массив;
МассивПриемников.Добавить(Подразделение1);
МассивПриемников.Добавить(Подразделение2);

ЗаписьРегистра = РегистрыСведений.НастройкиПередачи.СоздатьМенеджерЗаписи();
ЗаписьРегистра.ПодразделениеИсточник = Источник;

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

ЗаписьРегистра.Записать();

Важно: Этот метод делает невозможным эффективный отбор в запросе по условию «ГДЕ ПодразделениеПриемник = &НужноеПодразделение». Используйте его только для вспомогательных данных.

Решение 4. Использование Хранилища Значения в ресурсе

Если список подразделений не должен участвовать в ключе уникальности (то есть он не является «измерением»), мы можем перенести его в ресурс регистра с типом ХранилищеЗначения. Рассмотрим, как это работает:

В измерении остается только ПодразделениеИсточник. В ресурсе ДанныеПриемников мы храним сериализованный массив. Платформа 1С берет на себя сжатие и хранение этого объекта.


// Пример получения данных
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ДанныеПриемников ИЗ РегистрСведений.НастройкиПередачи ГДЕ ПодразделениеИсточник = &Источник";
// ... выполнение запроса
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
    СписокПриемников = Выборка.ДанныеПриемников.Получить(); // Получаем исходный массив
КонецЕсли;

Решение 5. Битовые маски (для профи)

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

Например: Подразделение А = 1, Подразделение Б = 2, Подразделение В = 4. Если в списке должны быть А и В, мы запишем число 5 (1+4). В языке запросов 1С работать с битами сложно, но для хранения это самый компактный вариант.

Архитектурные выводы

Мы рассмотрели различные подходы к решению задачи. Выбор конкретного метода зависит от ваших требований:

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

← На главную