Разработка и Конфигурация · 11 мин
Как обращаться к метаданным в 1С
Как программно обращаться к метаданным в 1С: объект Метаданные, поиск объектов конфигурации, получение реквизитов и табличных частей, примеры кода и типичные ошибки.
Метаданные в 1С — это описание структуры конфигурации: какие существуют справочники, документы, регистры, какие у них реквизиты, табличные части, измерения и ресурсы. Программный доступ к этой информации нужен, когда код должен работать универсально — например, обрабатывать любой документ, не зная заранее его типа, строить динамические отчёты или проверять наличие реквизита перед обращением к нему.
Доступ к метаданным осуществляется через глобальный объект Метаданные и метод Метаданные(), который есть у большинства объектов платформы. Через них можно получить имя объекта, его синоним, состав реквизитов, признаки использования и многое другое — всё это доступно только для чтения, изменить конфигурацию из кода нельзя.
Материал рассчитан на разработчиков, которые уже знакомы со встроенным языком 1С и хотят уверенно работать с коллекциями метаданных в управляемом приложении и обычных формах.
Глобальный объект Метаданные и навигация по конфигурации
Глобальный контекст встроенного языка содержит свойство Метаданные, через которое доступна вся структура конфигурации. Коллекции верхнего уровня соответствуют видам объектов: Метаданные.Справочники, Метаданные.Документы, Метаданные.РегистрыСведений, Метаданные.РегистрыНакопления, Метаданные.Перечисления и так далее.
Обратиться к конкретному объекту можно по имени как к свойству или через метод Найти(), когда имя хранится в строковой переменной:
// Прямое обращение по имени
МД = Метаданные.Справочники.Номенклатура;
// Поиск по строковому имени
ИмяОбъекта = "Номенклатура";
МД = Метаданные.Справочники.Найти(ИмяОбъекта);
Если МД = Неопределено Тогда
Сообщить("Объект с именем " + ИмяОбъекта + " не найден");
КонецЕсли;
Метод Найти() возвращает Неопределено, если объекта нет, поэтому его безопаснее использовать в универсальных механизмах, где имя объекта приходит из настроек или от пользователя. Прямое обращение через точку при отсутствующем объекте вызовет ошибку времени выполнения.
Получение метаданных конкретного объекта
У ссылок, объектов данных и записей регистров есть метод Метаданные(), который возвращает описание конфигурации именно этого объекта. Это основной способ в универсальном коде, когда тип значения заранее неизвестен:
МД = СсылкаНаОбъект.Метаданные();
Сообщить("Полное имя: " + МД.ПолноеИмя()); // "Справочник.Номенклатура"
Сообщить("Имя: " + МД.Имя); // "Номенклатура"
Сообщить("Синоним: " + МД.Синоним); // "Номенклатура" (представление)
Сообщить("Представление: " + МД.Представление());
Метод ПолноеИмя() особенно полезен: он возвращает строку вида «Документ.РеализацияТоваровУслуг», которую можно сохранить в базе, а потом по ней восстановить объект метаданных через Метаданные.НайтиПоПолномуИмени():
МД = Метаданные.НайтиПоПолномуИмени("Документ.РеализацияТоваровУслуг");
Обратная задача — определить, к какому виду относится значение — решается проверкой Метаданные.Документы.Содержит(МД) или анализом полного имени по точке.
Перебор коллекций метаданных
Коллекции метаданных можно перебирать в цикле — так строятся списки всех документов конфигурации, обработчики обмена и универсальные отчёты:
Для Каждого МДДокумент Из Метаданные.Документы Цикл
Сообщить(МДДокумент.Имя + " — " + МДДокумент.Синоним);
КонецЦикла;
У коллекций есть методы Количество() и Получить(Индекс), поэтому возможен и обход по индексу, но цикл «Для Каждого» читается проще и меньше подвержен ошибкам. Порядок элементов в коллекции соответствует порядку объектов в конфигураторе.
- 1Откройте общий модуль или обработку, где нужен код
- 2Напишите цикл: Для Каждого МД Из Метаданные.Документы Цикл
- 3Внутри цикла обратитесь к МД.Имя и МД.Синоним
- 4Проверьте результат в режиме Предприятия — список должен совпадать с веткой «Документы» в конфигураторе
Работа с реквизитами и табличными частями
У объектов метаданных справочников, документов и обработок есть коллекция Реквизиты, а также ТабличныеЧасти, у каждой из которых — свои реквизиты. Через них можно программно узнать состав полей объекта:
МД = Метаданные.Документы.РеализацияТоваровУслуг;
// Реквизиты шапки
Для Каждого Реквизит Из МД.Реквизиты Цикл
Сообщить(Реквизит.Имя + " : " + Строка(Реквизит.Тип));
КонецЦикла;
// Табличные части и их колонки
Для Каждого ТЧ Из МД.ТабличныеЧасти Цикл
Сообщить("Табличная часть: " + ТЧ.Имя);
Для Каждого Колонка Из ТЧ.Реквизиты Цикл
Сообщить(" " + Колонка.Имя);
КонецЦикла;
КонецЦикла;
Свойство Тип реквизита возвращает объект ОписаниеТипов — из него можно узнать, составной ли тип, какие конкретно типы входят в состав, длину строки и точность числа. Это используется при динамическом построении форм и таблиц значений.
Помимо явных реквизитов у объектов есть стандартные реквизиты (Ссылка, Код, Наименование, Дата, Номер, Проведен и другие) — они доступны через коллекцию СтандартныеРеквизиты и не входят в Реквизиты. Это частая причина «пропавших» полей при переборе.
Метаданные регистров: измерения, ресурсы, реквизиты
У регистров сведений и накопления структура описывается тремя коллекциями: Измерения, Ресурсы и Реквизиты. Разделение принципиально: измерения определяют разрез хранения, ресурсы — хранимые значения, реквизиты — дополнительную информацию.
МД = Метаданные.РегистрыНакопления.ТоварыНаСкладах;
Для Каждого Измерение Из МД.Измерения Цикл
Сообщить("Измерение: " + Измерение.Имя);
КонецЦикла;
Для Каждого Ресурс Из МД.Ресурсы Цикл
Сообщить("Ресурс: " + Ресурс.Имя);
КонецЦикла;
Дополнительно у регистров доступны свойства вида: для регистра сведений — РежимЗаписи и ПериодичностьРегистраСведений, для регистра накопления — ВидРегистраНакопления (остатки или обороты). Эти признаки важно учитывать в универсальных механизмах выгрузки, потому что от них зависит, есть ли у регистра поле «Период» и как формируются итоги.
Проверка прав доступа и функциональных опций
Наличие объекта в метаданных не гарантирует, что текущий пользователь может с ним работать. Перед обращением к данным в универсальном коде проверяйте права через ПравоДоступа():
Если ПравоДоступа("Чтение", Метаданные.Документы.РеализацияТоваровУслуг) Тогда
// можно выполнять запрос к документу
КонецЕсли;
Аналогичная ситуация с функциональными опциями: объект может существовать в конфигурации, но быть скрыт настройками. Проверка выполняется через ПолучитьФункциональнуюОпцию(). Внешний вид интерфейса при этом меняется автоматически, а вот программный код к данным обратиться всё равно сможет — функциональные опции ограничивают видимость, а не права.
Практические сценарии и ограничения
Типовые задачи, где обращение к метаданным неизбежно: универсальные обработки загрузки и выгрузки (обход реквизитов произвольного объекта), динамическое построение запросов, проверка заполненности обязательных полей по произвольному виду документа, механизмы логирования изменений, работающие для любых объектов.
Пример универсальной проверки наличия реквизита перед обращением — защищает код от падения при различиях конфигураций:
Функция ЕстьРеквизит(ИмяРеквизита, МД)
Возврат МД.Реквизиты.Найти(ИмяРеквизита) <> Неопределено;
КонецФункции;
Если ЕстьРеквизит("Организация", Ссылка.Метаданные()) Тогда
Организация = Ссылка.Организация;
КонецЕсли;
Из ограничений стоит помнить: метаданные недоступны в некоторых контекстах внешних соединений и фоновых заданий с ограниченным контекстом, объекты метаданных нельзя сериализовать и передать между сеансами — передавайте полное имя строкой. Также обращение к метаданным возможно только на сервере и в толстом клиенте; в клиентском контексте управляемой формы прямой работы с коллекциями метаданных нет, нужен серверный вызов.
Как проверить результат
Переменная содержит объект, ПолноеИмя() возвращает строку вида «Вид.Имя»
Переменная равна Неопределено — объект с таким именем не найден
В списке есть прикладные реквизиты; стандартные поля получены отдельно через СтандартныеРеквизиты
В списке нет полей Ссылка, Дата, Номер — вы смотрите только Реквизиты
ПравоДоступа проверено, недоступные объекты пропускаются
Код падает с ошибкой нарушения прав доступа
Что важно запомнить
Метаданные читаются через глобальное свойство Метаданные или метод Метаданные() у объекта. Используйте Найти() и НайтиПоПолномуИмени() для безопасного поиска, помните про отдельные коллекции СтандартныеРеквизиты, Измерения и Ресурсы, проверяйте ПравоДоступа и учитывайте, что в управляемом клиенте работа с метаданными выполняется на сервере.
Частые вопросы
Как узнать тип значения, если оно может быть любым объектом конфигурации?
Получите метаданные значения через Значение.Метаданные() и сравните с нужным объектом: Если МД = Метаданные.Документы.РеализацияТоваровУслуг Тогда. Для проверки принадлежности к виду в целом используйте Метаданные.Документы.Содержит(МД). Для примитивных типов метод Метаданные() отсутствует — их проверяют через ТипЗнч().
Почему Метаданные.Справочники.Найти() возвращает Неопределено?
Чаще всего имя указано с ошибкой или объект был переименован/удалён при обновлении конфигурации. Проверьте точное имя в конфигураторе — оно чувствительно к написанию, хотя регистр букв роли не играет. Также убедитесь, что ищете в правильной коллекции: документ не найдётся в коллекции справочников.
Можно ли изменить метаданные программно из кода 1С?
Нет, встроенный язык предоставляет доступ к метаданным только на чтение. Изменение структуры выполняется в конфигураторе, через расширения конфигурации или механизмы загрузки конфигурации из файлов. Попытки обойти это внешними средствами нарушают целостность базы.
Как получить список объектов, у которых есть конкретный реквизит?
Пройдите циклом по нужным коллекциям (Справочники, Документы и др.) и для каждого объекта проверьте МД.Реквизиты.Найти(ИмяРеквизита) <> Неопределено. Такой подход используется, например, для поиска всех документов с реквизитом «Организация» при настройке разграничения данных.
Работает ли обращение к метаданным на клиенте в управляемых формах?
Нет, в клиентском контексте управляемой формы объект Метаданные недоступен — компилятор выдаст ошибку. Вынесите логику в серверную процедуру с директивой &НаСервере или в серверный общий модуль, а на клиент возвращайте готовые структуры данных: имена, синонимы, списки реквизитов.
Чем ПолноеИмя() лучше простого Имя при сохранении настроек?
Имя без вида объекта неоднозначно: справочник и документ могут называться одинаково. ПолноеИмя() возвращает строку «Вид.Имя», которая однозначно идентифицирует объект и восстанавливается через Метаданные.НайтиПоПолномуИмени(), поэтому именно её сохраняют в настройках универсальных механизмов.