Почему реквизит документа не может иметь тип «Список значений» и как это реализовать?

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

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

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

Архитектурные причины: Почему БД «сопротивляется» Спискам значений

Разберем ситуацию с точки зрения хранения данных. Когда мы создаем реквизит у документа, платформа 1С должна зарезервировать для него место в физической таблице базы данных (MS SQL, PostgreSQL или встроенный файловый движок). Каждый обычный реквизит объекта — это одна колонка в строке таблицы. Эта колонка должна иметь строго определенный тип данных: число, дата, строка фиксированной или неограниченной длины, либо ссылка (GUID).

Проанализируем структуру объекта СписокЗначений. Это не просто массив значений, это сложная коллекция, где каждый элемент состоит из:

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

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

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

Разница между Списком значений и Табличной частью

Часто в обсуждениях возникает мнение, что СписокЗначений — это та же табличная часть, только с одной колонкой. Давайте выясним причину, почему это не совсем так. Рассмотрим основные отличия:

Способ 1: Использование Хранилища значений

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

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


// Пример записи Списка значений в реквизит объекта
СписокДляЗаписи = Новый СписокЗначений;
СписокДляЗаписи.Добавить("Параметр1", "Первое значение");
СписокДляЗаписи.Добавить(100, "Числовой параметр");

ОбъектДокумент = РеквизитФормыВЗначение("Объект");
ОбъектДокумент.ДополнительныеПараметры = Новый ХранилищеЗначения(СписокДляЗаписи);
ОбъектДокумент.Записать();

Для восстановления данных при открытии формы выполним обратное преобразование:


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

Важно: Помните, что данные внутри ХранилищаЗначения сжаты и хранятся в бинарном виде. Вы не сможете написать запрос типа ГДЕ ДополнительныеПараметры СОДЕРЖИТ "Параметр1". Это решение подходит только для «технического» хранения данных.

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

Более современный и «прозрачный» метод — преобразование списка в строку формата JSON. Это удобнее тем, что при отладке или просмотре базы через консоль запросов вы увидите текст, а не бинарные данные. Для этого реквизит должен иметь тип Строка (неограниченной длины).

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


// Превращаем список значений в строку JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, МойСписокЗначений);
СтрокаДляХранения = ЗаписьJSON.Закрыть();
// Теперь записываем СтрокаДляХранения в обычный реквизит типа Строка

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

Способ 3: Табличная часть — классический путь

Если вам нужно, чтобы данные из списка были доступны в отчетах, необходимо использовать Табличную часть. Это самый правильный путь с точки зрения производительности и архитектуры 1С. Чтобы интерфейсно это выглядело как список значений, вы можете просто скрыть лишние кнопки командной панели и оставить только одну колонку Значение.

Проанализируем преимущества этого подхода:

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

Способ 4: Реквизиты формы и программное заполнение

Бывают ситуации, когда список нужен только для удобства пользователя во время редактирования, а в базе должны оказаться только результаты его выбора. В этом случае мы создаем реквизит с типом СписокЗначений непосредственно в Форме документа (не в самом объекте!).

Рассмотрим алгоритм работы:

Резюме

Мы выяснили, что отсутствие типа СписокЗначений в реквизитах объектов — это не программная ошибка, а следствие строгой структуры реляционных баз данных. Для решения задачи хранения множественных значений мы рекомендуем:

← На главную