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