Как перенести иерархию справочника в реквизиты и настроить зависимый выбор в 1С?

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

При работе со справочниками в 1С часто возникает ситуация, когда стандартная древовидная структура (папки/группы) становится неудобной или недостаточно гибкой. Например, когда требуется жестко регламентировать количество уровней вложенности (Класс — Подкласс — Группа) или выводить иерархию в отчетах в виде отдельных колонок. Рассмотрим подробно, как перенести логику иерархии в реквизиты элемента и обеспечить удобный интерфейс выбора для пользователя.

Почему стандартная иерархия иногда не подходит?

Прежде чем переходить к реализации, проанализируем ситуацию. Стандартная иерархия 1С (поле Родитель) имеет ряд ограничений:

Перенос уровней в отдельные реквизиты типа СправочникСсылка позволяет сделать структуру более строгой и предсказуемой.

Вариант 1. Программное управление формой выбора (для обычных форм)

Рассмотрим случай, когда мы хотим оставить структуру папок в справочнике "Адреса" или "Номенклатура", но на форме другого объекта (например, "Контрагент") выбирать уровни иерархии в отдельные поля. Выясним причину популярности этого метода: он не требует изменения структуры хранения данных, а лишь меняет логику интерфейса.

Для реализации нам понадобится обработчик события НачалоВыбора для реквизита. Разберем по шагам логику для выбора "Района", который должен находиться внутри выбранной ранее "Области":


Процедура адрРайонНачалоВыбора(Элемент, СтандартнаяОбработка)
    // Если область не выбрана, можно либо запретить выбор, либо открывать корень
    Если адрОбласть.Пустая() Тогда 
        Возврат; 
    КонецЕсли;

    Группа = Справочники.Адреса.НайтиПоКоду(адрОбласть.Код);
    Если Не Группа.Пустая() Тогда    
        СтандартнаяОбработка = Ложь; // Отключаем стандартное открытие
        ФормаВыбора = Справочники.Адреса.ПолучитьФормуВыбора(, Элемент); 
        
        // Настраиваем дерево для удобства навигации
        ФормаВыбора.ЭлементыФормы.ТабличноеПоле1.ИерархическийПросмотр = Истина;
        
        // Устанавливаем фильтр: показывать только содержимое выбранной области
        ФормаВыбора.ЭлементыФормы.ТабличноеПоле1.ТекущийРодитель = Группа;
        
        // Позиционируемся на уже выбранном значении, если оно есть
        ФормаВыбора.ЭлементыФормы.ТабличноеПоле1.ТекущаяСтрока = адрРайон;
        
        ФормаВыбора.Открыть();    
    КонецЕсли;
КонецПроцедуры

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

Вариант 2. Использование связанных подчиненных справочников

Если задача стоит избавиться от иерархии внутри одного справочника совсем, проанализируем архитектуру с подчиненными справочниками. Мы создаем 5 отдельных справочников (Классы, Подклассы, Группы и т.д.), где каждый следующий подчинен предыдущему (свойство Владелец).

В этом случае на форме основного элемента мы размещаем 5 реквизитов. Настройка связей в управляемых формах (v8.3) становится тривиальной. Рассмотрим использование механизма Связи параметров выбора:

  1. Откройте свойства реквизита Подкласс.
  2. Найдите пункт Связи параметров выбора.
  3. Добавьте связь: Отбор.Владелец(Класс).

Теперь платформа автоматически при нажатии кнопки выбора в поле Подкласс покажет только те записи, владельцем которых является объект, указанный в поле Класс. Это наиболее современный и "чистый" с точки зрения кода способ.

Вариант 3. Плоская структура и дерево фильтров

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

Посмотрим на пример реализации фильтров:

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

Технические нюансы и оптимизация

При переносе иерархии в реквизиты важно помнить о производительности. Проанализируем важные моменты:

Индексирование: Если вы планируете выполнять поиск или строить отчеты по реквизитам "Класс", "Подкласс" и т.д., обязательно установите свойство Индексировать (или Индексировать с доп. упорядочиванием) для этих полей в конфигураторе. Без индексов выборка по классификатору на большой базе будет крайне медленной.

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


&НаКлиенте
Процедура КлассПриИзменении(Элемент)
    // Очищаем зависимые поля, так как старые значения больше не актуальны
    Объект.Подкласс = ПредопределенноеЗначение("Справочник.Подклассы.ПустаяСсылка");
    Объект.ГруппаТоваров = ПредопределенноеЗначение("Справочник.ГруппыТоваров.ПустаяСсылка");
КонецПроцедуры

Резюме

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

Помните, что удобство интерфейса для пользователя ("минимум геморроя") достигается за счет автоматизации: автоматического открытия нужных папок, очистки неактуальных зависимых полей и наглядности фильтров в списке.

← На главную