Как получить свойства метаданных (например, ПериодичностьНомераДокумента) в запросе 1С?

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

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

Почему нельзя обратиться к метаданным напрямую из запроса?

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

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

Тем не менее, если мы пишем универсальный запрос (например, обработку для проверки нумерации всех документов в базе), нам необходимо как-то передать эти свойства внутрь. Рассмотрим подробнее рабочие альтернативы.

Решение 1: Использование временных таблиц (Рекомендуемый способ)

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

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

  1. Перед выполнением запроса мы программно обходим нужную ветку метаданных (например, Метаданные.Документы).
  2. Заполняем таблицу значений, где одной колонкой будет выступать тип документа (или пустая ссылка нужного типа), а другой — нужное свойство метаданных (периодичность).
  3. Передаем эту таблицу как параметр в запрос.
  4. Помещаем переданную таблицу во временную таблицу средствами языка запросов.
  5. Соединяем основные данные с нашей временной таблицей, используя функцию ТИПЗНАЧЕНИЯ().

Посмотрим на пример кода:


// 1. Подготовка таблицы значений с данными метаданных
ТаблицаМетаданных = Новый ТаблицаЗначений;
ТаблицаМетаданных.Колонки.Добавить("ТипДокумента");
ТаблицаМетаданных.Колонки.Добавить("Периодичность");

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

// 2. Передача данных в запрос и использование Временной Таблицы
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|    ТаблицаМД.ТипДокумента КАК ТипДокумента,
|    ТаблицаМД.Периодичность КАК Периодичность
|ПОМЕСТИТЬ ВТ_СвойстваМетаданных
|ИЗ
|    &ТаблицаМетаданных КАК ТаблицаМД
|;
|
|ВЫБРАТЬ
|    Журнал.Ссылка КАК ДокументСсылка,
|    ВТ_СвойстваМетаданных.Периодичность КАК ПериодичностьНомера
|ИЗ
|    ЖурналДокументов.ВсеДокументы КАК Журнал
|        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_СвойстваМетаданных КАК ВТ_СвойстваМетаданных
|        ПО (ВТ_СвойстваМетаданных.ТипДокумента = ТИПЗНАЧЕНИЯ(Журнал.Ссылка))";

Запрос.УстановитьПараметр("ТаблицаМетаданных", ТаблицаМетаданных);
РезультатЗапроса = Запрос.Выполнить();

Такой подход позволяет сохранить текст запроса неизменным и избежать громоздких операторов выбора ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ.

Решение 2: Передача системных перечислений в параметры

Если ваш запрос не является абсолютно универсальным для всех документов конфигурации, а работает лишь с несколькими конкретными типами, вы можете передавать значения свойств метаданных точечно. Системные перечисления метаданных, такие как ПериодичностьНомераДокумента.Год, ПериодичностьНомераДокумента.Месяц, ПериодичностьНомераДокумента.Непериодический, являются валидными значениями для платформы.

Вы можете передать их в параметры и использовать прямо в условиях запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|    Док.Ссылка КАК Документ
|ИЗ
|    Документ.ПоступлениеТоваровУслуг КАК Док
|ГДЕ
|    &ПериодичностьПоступления = &ПериодичностьГод";

Запрос.УстановитьПараметр("ПериодичностьПоступления", Метаданные.Документы.ПоступлениеТоваровУслуг.ПериодичностьНомера);
Запрос.УстановитьПараметр("ПериодичностьГод", ПериодичностьНомераДокумента.Год);

Решение 3: Динамическое формирование текста запроса

Если по каким-то причинам использовать временные таблицы нецелесообразно (например, если логика запроса кардинально меняется в зависимости от свойств объекта), остается метод конкатенации строк. Мы формируем текст запроса программно перед его выполнением, вставляя нужные нам условия.


ТекстЗапроса = "ВЫБРАТЬ Ссылка ИЗ Документ.АвансовыйОтчет ГДЕ ";

Если Метаданные.Документы.АвансовыйОтчет.ПериодичностьНомера = ПериодичностьНомераДокумента.Год Тогда
    ТекстЗапроса = ТекстЗапроса + "ДАТАВРЕМЯ(ГОД, Дата) = &ТекущийГод";
Иначе
    ТекстЗапроса = ТекстЗапроса + "ИСТИНА";
КонецЕсли;

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

Оптимизация при программном доступе к метаданным

Если вы собираете данные о документах или справочниках до выполнения запроса в циклах (как в первом решении), обращайте внимание на производительность получения метаданных. Доступ к метаданным конкретного объекта через методы Метаданные.НайтиПоТипу(ТипЗначения) или через вызов Объект.Метаданные() (если объект уже получен) работает быстрее, чем поиск по имени через глобальную коллекцию Метаданные.Документы[ИмяДокумента]. Обязательно учитывайте этот нюанс при разработке универсальных механизмов массовой обработки данных.

← На главную