При разработке сложных механизмов анализа конфигурации, например, при проверке прав доступа или выгрузке структуры базы данных, программисты часто сталкиваются с ситуацией, когда условие Если ТипЗнч(Объект) = Тип("СправочникСсылка.Имя") просто не выполняется, хотя визуально данные кажутся верными. Рассмотрим подробнее, почему это происходит, разберем разницу между типами данных и объектами метаданных, и выясним, как написать корректный и универсальный код.
Проанализируем типичный сценарий, с которого началось обсуждение. Разработчик использует функцию ПолучитьСтруктуруХраненияБазыДанных(), которая возвращает таблицу значений с описанием таблиц СУБД. В этой таблице есть колонка Метаданные. Ошибка заключается в предположении, что в этой колонке содержатся сами объекты метаданных или ссылки. На самом деле, эта функция возвращает полное имя объекта метаданных в виде строки (например, "Справочник.Организации").
Посмотрим на пример некорректного кода, который часто пытаются использовать:
Для каждого СтрСтруктуры Из ТаблицаСтруктуры Цикл
// ОШИБКА: СтрСтруктуры.Метаданные — это Строка, а не тип
Если ТипЗнч(СтрСтруктуры.Метаданные) = Тип("СправочникСсылка.Организации") Тогда
Сообщить("Это организации");
КонецЕсли;
КонецЦикла;
В данном случае условие никогда не будет истинным, так как тип значения СтрСтруктуры.Метаданные всегда будет Строка, а функция Тип() возвращает идентификатор типа данных 1С. Сравнение строки с типом данных в 1С всегда дает Ложь.
Для понимания того, как правильно выполнять проверку, проанализируем три принципиально разных понятия в платформе 1С:
"Справочник.Организации". Это имя, по которому мы можем найти объект, но само по себе оно не обладает свойствами объекта конфигурации.Метаданные. Например: Метаданные.Справочники.Организации. Тип самого этого описания всегда будет равен ОбъектМетаданных.Тип("СправочникСсылка.Организации"). Этот идентификатор используется для сравнения типов конкретных данных (ссылок, объектов документов и т.д.).Важный нюанс: У объекта метаданных нет прямого свойства Тип. Поэтому конструкция Метаданные.Справочники.Организации.Тип выдаст ошибку. Чтобы проверить, относится ли объект метаданных к конкретному типу ссылки, нужно использовать специальные методы.
Если у нас на руках есть строка с полным именем объекта (как в случае с ПолучитьСтруктуруХраненияБазыДанных), нам нужно сначала преобразовать её в объект метаданных, чтобы работать с ним дальше. Разберем, как это сделать правильно:
// Допустим, ИмяОбъектаСтрокой = "Справочник.Организации"
ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ИмяОбъектаСтрокой);
Если ОбъектМетаданных = Метаданные.Справочники.Организации Тогда
Сообщить("Объект найден и это Справочник Организации");
КонецЕсли;
Этот способ идеален, если вы хотите сравнить полученную строку с конкретным известным вам объектом конфигурации.
Выясним одну важную особенность функции ПравоДоступа(). Многие разработчики тратят время на преобразование строк в объекты метаданных перед вызовом этой функции. Однако ПравоДоступа() достаточно универсальна: она может принимать вторым параметром как сам ОбъектМетаданных, так и его полное имя в виде строки.
Проанализируем пример эффективного кода для проверки прав на чтение для всех объектов из структуры хранения:
мТЗ = ПолучитьСтруктуруХраненияБазыДанных();
РолиДляПроверки = Метаданные.Роли;
Для Каждого эл Из мТЗ Цикл
ПолноеИмя = эл.Метаданные; // Это строка, например "Документ.РеализацияТоваровУслуг"
Если ПустаяСтрока(ПолноеИмя) Тогда
Продолжить;
КонецЕсли;
Для Каждого Роль Из РолиДляПроверки Цикл
// Передаем строку прямо в функцию — это работает быстро!
Если ПравоДоступа("Чтение", ПолноеИмя, Роль) Тогда
Сообщить("Роль " + Роль.Имя + " имеет право на чтение " + ПолноеИмя);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Иногда задача стоит иначе: у вас есть не строка, а некая переменная с данными, и вы хотите понять, относится ли она к тому же метаобъекту, что и ваша строка. В этом случае лучше всего использовать метод получения объекта метаданных от ссылки.
Рассмотрим ситуацию, когда в списке значений хранятся ссылки, и мы хотим сравнить их с объектом метаданных:
Для Каждого ЭлементСписка Из СписокЗн Цикл
СсылкаНаОбъект = ЭлементСписка.Значение;
// Получаем объект метаданных от конкретной ссылки
МетаданныеОбъекта = СсылкаНаОбъект.Метаданные();
// Сравниваем с целевым объектом метаданных
Если МетаданныеОбъекта = Метаданные.Справочники.Организации Тогда
Сообщить("Это ссылка на справочник Организации");
КонецЕсли;
КонецЦикла;
Если вы написали код, и он не заходит в условие Если, проанализируйте ситуацию с помощью функции Сообщить() или табло отладчика. Выполните следующие команды:
Сообщить(ТипЗнч(ВашаПеременная)); — если вы видите "Строка", значит сравнение с Тип("...") не сработает.Сообщить(ВашаПеременная); — посмотрите на само значение. Объект метаданных при выводе в сообщение часто выглядит как "Справочник.Организации", что может сбить с толку и заставить думать, что это строка.Метаданные.НайтиПоТипу(ТипЗнч(ВашаПеременная)), чтобы быстро получить объект метаданных из любой ссылки или объекта.Помните, что платформа 1С строго разделяет описание конфигурации (Метаданные) и сами данные (Ссылки, Объекты). Правильное понимание того, в какой момент вы работаете со строковым именем, а в какой — с идентификатором типа, позволит вам писать надежный и производительный код без лишних преобразований.