Почему не срабатывает проверка на тип при работе с метаданными в 1С и как это исправить

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

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

Разберем ситуацию: в чем заключается основная ошибка

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

Посмотрим на пример некорректного кода, который часто пытаются использовать:


Для каждого СтрСтруктуры Из ТаблицаСтруктуры Цикл
    // ОШИБКА: СтрСтруктуры.Метаданные — это Строка, а не тип
    Если ТипЗнч(СтрСтруктуры.Метаданные) = Тип("СправочникСсылка.Организации") Тогда
        Сообщить("Это организации");
    КонецЕсли;
КонецЦикла;

В данном случае условие никогда не будет истинным, так как тип значения СтрСтруктуры.Метаданные всегда будет Строка, а функция Тип() возвращает идентификатор типа данных 1С. Сравнение строки с типом данных в 1С всегда дает Ложь.

Анализируем типы: Строка vs ОбъектМетаданных vs Тип

Для понимания того, как правильно выполнять проверку, проанализируем три принципиально разных понятия в платформе 1С:

  1. Строка (String): Это просто текстовое представление. Например, "Справочник.Организации". Это имя, по которому мы можем найти объект, но само по себе оно не обладает свойствами объекта конфигурации.
  2. ОбъектМетаданных (MetadataObject): Это структурное описание объекта в конфигураторе. Получить его можно через глобальный контекст Метаданные. Например: Метаданные.Справочники.Организации. Тип самого этого описания всегда будет равен ОбъектМетаданных.
  3. Тип (Type): Это идентификатор типа данных, которые хранятся в базе. Например, Тип("СправочникСсылка.Организации"). Этот идентификатор используется для сравнения типов конкретных данных (ссылок, объектов документов и т.д.).

Важный нюанс: У объекта метаданных нет прямого свойства Тип. Поэтому конструкция Метаданные.Справочники.Организации.Тип выдаст ошибку. Чтобы проверить, относится ли объект метаданных к конкретному типу ссылки, нужно использовать специальные методы.

Способ 1: Использование метода НайтиПоПолномуИмени()

Если у нас на руках есть строка с полным именем объекта (как в случае с ПолучитьСтруктуруХраненияБазыДанных), нам нужно сначала преобразовать её в объект метаданных, чтобы работать с ним дальше. Разберем, как это сделать правильно:


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

Если ОбъектМетаданных = Метаданные.Справочники.Организации Тогда
    Сообщить("Объект найден и это Справочник Организации");
КонецЕсли;

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

Способ 2: Проверка прав доступа через строковое имя

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

Проанализируем пример эффективного кода для проверки прав на чтение для всех объектов из структуры хранения:


мТЗ = ПолучитьСтруктуруХраненияБазыДанных();
РолиДляПроверки = Метаданные.Роли;

Для Каждого эл Из мТЗ Цикл
    ПолноеИмя = эл.Метаданные; // Это строка, например "Документ.РеализацияТоваровУслуг"
    
    Если ПустаяСтрока(ПолноеИмя) Тогда
        Продолжить;
    КонецЕсли;

    Для Каждого Роль Из РолиДляПроверки Цикл
        // Передаем строку прямо в функцию — это работает быстро!
        Если ПравоДоступа("Чтение", ПолноеИмя, Роль) Тогда
            Сообщить("Роль " + Роль.Имя + " имеет право на чтение " + ПолноеИмя);
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Способ 3: Сравнение через пустую ссылку (самый надежный для типов)

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

Рассмотрим ситуацию, когда в списке значений хранятся ссылки, и мы хотим сравнить их с объектом метаданных:


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

Как не запутаться: советы по отладке

Если вы написали код, и он не заходит в условие Если, проанализируйте ситуацию с помощью функции Сообщить() или табло отладчика. Выполните следующие команды:

  1. Сообщить(ТипЗнч(ВашаПеременная)); — если вы видите "Строка", значит сравнение с Тип("...") не сработает.
  2. Сообщить(ВашаПеременная); — посмотрите на само значение. Объект метаданных при выводе в сообщение часто выглядит как "Справочник.Организации", что может сбить с толку и заставить думать, что это строка.
  3. Используйте Метаданные.НайтиПоТипу(ТипЗнч(ВашаПеременная)), чтобы быстро получить объект метаданных из любой ссылки или объекта.

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

← На главную