При проектировании структуры данных в 1С часто возникает желание сделать код максимально читаемым и логичным. Одна из распространенных идей — создать иерархический справочник (например, "Свойства"), создать в нем группы (например, "Цвета", "Положение"), а внутри групп разместить предопределенные элементы. Логичным продолжением этой идеи кажется возможность обращаться к этим элементам в программном коде, используя синтаксис, повторяющий структуру дерева: Справочники.Свойства.Цвета.Зеленый.
Давайте разберем подробно, почему платформа 1С устроена определенным образом, какие ограничения существуют для предопределенных элементов и какие архитектурные решения мы можем применить для реализации подобной задачи.
Для начала проанализируем, как платформа 1С воспринимает предопределенные элементы. Когда мы создаем элемент в конфигураторе, мы задаем ему свойство Имя. Это имя является идентификатором объекта метаданных. Ключевой момент здесь заключается в том, что Имя должно быть уникальным в пределах всего объекта метаданных (всего Справочника), а не в пределах конкретной группы.
Рассмотрим разницу между тем, как мы видим данные, и как их видит платформа:
Справочники.ИмяСправочника.ИмяПредопределенного работает напрямую с таблицей предопределенных имен. В этой таблице нет понятия иерархии. Группа "Цвета" — это один предопределенный элемент, а элемент "Зеленый" — это другой, совершенно независимый с точки зрения метаданных элемент.Именно поэтому попытка написать Справочники.Свойства.Цвета.Зеленый приведет к синтаксической ошибке или ошибке исполнения. Платформа попытается найти у элемента "Цвета" (который является ссылкой) свойство "Зеленый", но такого свойства у ссылки нет.
Давайте выясним техническую причину ограничения. Если бы платформа позволяла создавать элементы с одинаковым именем "Зеленый" в разных группах (например, в группе "Цвета" и в группе "Статусы"), то при обращении из кода возникла бы неопределенность. Уникальность идентификатора (Имени) гарантирует, что, написав Справочники.Свойства.Зеленый, мы получим конкретную ссылку.
Следовательно, иерархия в справочниках — это свойство данных (значение реквизита "Родитель"), а не свойство конфигурации (структура объектов).
Поскольку мы выяснили, что имя должно быть уникальным, самым надежным и простым способом является включение названия группы в само имя предопределенного элемента при его создании в конфигураторе.
Вместо желаемой структуры .Цвета.Зеленый, мы создаем предопределенные элементы со следующими именами:
Цвета_ЗеленыйЦвета_КрасныйПоложение_ВерхПоложение_ЛевоТогда в коде обращение будет выглядеть следующим образом:
// Обращение к элементу
ТекущийЦвет = Справочники.Свойства.Цвета_Зеленый;
// Обращение к группе (если она тоже предопределенная)
РодительскаяГруппа = Справочники.Свойства.Цвета;
Это полностью решает задачу уникальности и позволяет сохранить некоторую логическую группировку за счет префиксов в именах. Да, это не дает "точечной" нотации (dot syntax) для вложенности, но это стандартный подход в 1С.
Если ваша задача — хранить фиксированный список значений, которые никогда не будут меняться пользователем, давайте рассмотрим объект Перечисление. Это наиболее близкий аналог для хранения списка опций.
Обращение к перечислению выглядит так:
ТекущийЦвет = Перечисления.Цвета.Зеленый;
Однако, проанализируем ограничения этого подхода, которые были выявлены в обсуждении:
Если вам нужно получить строковое представление значения перечисления (синоним), используем функцию Строка():
// Вернет "Зеленый" (если это задано в синониме)
НазваниеЦвета = Строка(Перечисления.Цвета.Зеленый);
Если же требуется хранить соответствие "Зеленый" -> "green", для перечислений придется писать отдельную функцию, которая через Если...ИначеЕсли или Соответствие будет возвращать нужные данные, что усложняет поддержку кода.
Если для вас критически важен именно синтаксис Свойства.Группа.Элемент, и вы хотите объединить гибкость справочников (наличие реквизитов) с красотой кода, мы можем реализовать программную обертку. Давайте создадим механизм, который будет собирать нужную структуру.
Алгоритм реализации:
УправлениеСвойствами.Пример кода в общем модуле:
Функция ПолучитьДеревоСвойств() Экспорт
// 1. Подготавливаем структуру для Цветов
Цвета = Новый Структура;
// Здесь мы обращаемся к предопределенным элементам, названным плоско (см. Решение 1)
Цвета.Вставить("Зеленый", Справочники.Свойства.Цвета_Зеленый);
Цвета.Вставить("Красный", Справочники.Свойства.Цвета_Красный);
// 2. Подготавливаем структуру для Положения
Положение = Новый Структура;
Положение.Вставить("Верх", Справочники.Свойства.Положение_Верх);
Положение.Вставить("Низ", Справочники.Свойства.Положение_Низ);
// 3. Собираем общую структуру
ОбщиеСвойства = Новый Структура;
ОбщиеСвойства.Вставить("Цвета", Цвета);
ОбщиеСвойства.Вставить("Положение", Положение);
Возврат ОбщиеСвойства;
КонецФункции
Теперь в любом месте конфигурации мы можем использовать желанный синтаксис:
Свойства = УправлениеСвойствами.ПолучитьДеревоСвойств();
// Красивое обращение через точку
МойЦвет = Свойства.Цвета.Зеленый;
// Доступ к дополнительным реквизитам справочника
КодДляСайта = МойЦвет.КодДляAPI; // Вернет "green"
Плюсы и минусы этого подхода:
Преимущество очевидно: вы получаете идеальный автокомплит (если модуль возвращает фиксированную структуру и платформа сможет её проанализировать, либо если вы знаете структуру) и читаемый код.
Недостатком является необходимость поддерживать этот код. Если вы добавите новый предопределенный элемент в конфигураторе, вам придется руками добавить строчку в общий модуль. Если элементов сотни, этот метод становится трудоемким.
Давайте подытожим, какой подход лучше выбрать в зависимости от ваших целей:
Цвета_Зеленый).Платформа 1С жестко разграничивает пространство имен метаданных и иерархию данных в базе. Понимание этого принципа позволит вам избегать ошибок при проектировании архитектуры решения.