Как правильно установить условие по родителю в справочнике Идентификаторы объектов метаданных?

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

При работе с типовыми конфигурациями на базе Библиотеки стандартных подсистем (БСП) программисты часто сталкиваются со справочником Идентификаторы объектов метаданных. Этот справочник является техническим и хранит ссылки на все объекты метаданных конфигурации (справочники, документы, роли и т.д.), что позволяет использовать их в данных базы (например, в регистрах сведений для настройки прав доступа). Одной из частых задач является получение списка всех ролей через запрос, и здесь возникает вопрос: как правильно прописать условие в секции ГДЕ, чтобы отфильтровать элементы по родителю "Роли"?

В этой статье мы подробно разберем несколько подходов — от простых до наиболее оптимизированных и правильных с точки зрения архитектуры 1С.

Вариант 1. Фильтрация через обращение к наименованию родителя

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


ВЫБРАТЬ
    Идентификаторы.Ссылка КАК Ссылка,
    Идентификаторы.Наименование КАК Наименование
ИЗ
    Справочник.ИдентификаторыОбъектовМетаданных КАК Идентификаторы
ГДЕ
    Идентификаторы.Родитель.Наименование = "Роли"

Проанализируем этот подход: обращение через точку в языке запросов 1С на уровне СУБД превращается в неявное ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN). Если в справочнике очень много записей, это может незначительно снизить производительность. Однако главная проблема здесь в другом: фильтрация по строковому наименованию крайне ненадежна. В разных локализациях конфигурации или при случайном редактировании справочника администратором наименование группы может измениться, и запрос перестанет работать.

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

Многие системные справочники имеют предопределенные элементы, к которым можно обратиться через конструкцию ЗНАЧЕНИЕ(). Если бы узел "Роли" был предопределенным, мы бы написали условие следующим образом:


ГДЕ
    Идентификаторы.Родитель = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.Роли)

Но, как выяснилось в ходе обсуждения, в справочнике ИдентификаторыОбъектовМетаданных элементы заполняются программно при обновлении конфигурации и не являются предопределенными в метаданных. Поэтому попытка использовать ЗНАЧЕНИЕ() приведет к ошибке: "Неверные параметры".

Вариант 3. Использование подзапроса для поиска родителя

Если нам нужно решить задачу исключительно средствами языка запросов (например, в динамическом списке без возможности передать параметр в коде), можно применить вложенный запрос. Это позволяет найти ссылку на нужный узел по его имени и сопоставить её с полем Родитель основных данных.


ВЫБРАТЬ
    Идентификаторы.Ссылка
ИЗ
    Справочник.ИдентификаторыОбъектовМетаданных КАК Идентификаторы
ГДЕ
    Идентификаторы.Родитель В (
        ВЫБРАТЬ
            Внутренний.Ссылка
        ИЗ
            Справочник.ИдентификаторыОбъектовМетаданных КАК Внутренний
        ГДЕ
            Внутренний.Наименование = &НаименованиеРоли
    )

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

Вариант 4. Передача ссылки через параметр (Рекомендуемый способ)

Наиболее правильным с точки зрения производительности и надежности является предварительное получение ссылки на нужного родителя в коде на встроенном языке и последующая передача этой ссылки в параметр запроса. Выясним причину: когда мы передаем готовую ссылку, серверу СУБД не нужно выполнять дополнительные сравнения строк или соединения таблиц, поиск идет по внутреннему идентификатору (GUID).

Разберем, как это реализовать программно:


// 1. Сначала находим ссылку на родителя (группу "Роли")
СсылкаНаРодителя = Справочники.ИдентификаторыОбъектовМетаданных.НайтиПоНаименованию("Роли");

// 2. Устанавливаем параметр в запросе или динамическом списке
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Идентификаторы.Ссылка
    |ИЗ
    |   Справочник.ИдентификаторыОбъектовМетаданных КАК Идентификаторы
    |ГДЕ
    |   Идентификаторы.Родитель = &Родитель";

Запрос.УстановитьПараметр("Родитель", СсылкаНаРодителя);
Результат = Запрос.Выполнить();

Важное уточнение: если вы используете БСП, не ищите ссылку через НайтиПоНаименованию. В БСП есть специальный программный интерфейс для этого справочника.

Вариант 5. Использование возможностей БСП и реквизита "ПолноеИмя"

Давайте проанализируем структуру справочника ИдентификаторыОбъектовМетаданных подробнее. У него есть реквизит ПолноеИмя, который гораздо стабильнее Наименования. Для узла ролей ПолноеИмя обычно пустое, но для самих элементов оно имеет формат "Роль.ИмяРоли".

Чтобы получить ссылку на идентификатор метаданных максимально корректно, воспользуемся функцией общего модуля БСП:


// Получаем идентификатор конкретной роли или всей коллекции
СсылкаНаОбъект = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Роль");
// Теперь эту ссылку можно смело передавать в параметр ГДЕ Родитель = &Параметр

Преимущество функций БСП заключается в том, что они используют кэширование (через ПараметрыСеанса.ИдентификаторыОбъектовМетаданных). Это работает мгновенно и не нагружает базу данных повторными поисками.

Вариант 6. Учет иерархии

Если ваша задача — вытащить вообще все объекты, связанные с ролями, включая возможные подпапки (хотя в данном справочнике структура обычно плоская под основным узлом), лучше использовать условие В ИЕРАРХИИ. Рассмотрим пример с использованием подзапроса:


ГДЕ 
    Идентификаторы.Ссылка В ИЕРАРХИИ (
        ВЫБРАТЬ 
            Род.Ссылка 
        ИЗ 
            Справочник.ИдентификаторыОбъектовМетаданных КАК Род 
        ГДЕ 
            Род.Наименование = "Роли"
    )

Такой подход гарантирует, что если структура справочника станет более сложной, ваш код все равно будет корректно выбирать все дочерние элементы.

Подведем итоги

Подводя итог нашему анализу, можно выстроить следующую иерархию решений:

  1. Профессиональное решение: получить ссылку через ОбщегоНазначения.ИдентификаторОбъектаМетаданных() и передать её как параметр запроса. Это быстро, надежно и соответствует стандартам разработки 1С.
  2. Допустимое решение (для консоли запросов): использование подзапроса по Наименованию или ПолномуИмени, чтобы не искать ссылку вручную.
  3. Нежелательное решение: использование ГДЕ Родитель.Наименование = "Роли" из-за зависимости от строкового представления и неявных соединений в SQL.

Помните, что справочник идентификаторов — это "зеркало" ваших метаданных в данных, и работа с ним через системные механизмы БСП всегда будет более предпочтительной, чем прямые манипуляции со строками в запросах.

← На главную