При работе с полями составного типа данных (например, такими как Субконто, Владелец, Регистратор или любые произвольные дополнительные реквизиты) перед разработчиком часто возникает задача: определить, к какому именно классу метаданных относится текущее значение. Нам может потребоваться выяснить, является ли объект справочником или документом, не прибегая к жесткому перечислению десятков и сотен конкретных таблиц вручную.
В рамках этой статьи мы подробно разберем, почему простые интуитивные решения (так называемые «костыли») могут быть опасны для производительности вашей базы данных, и рассмотрим три надежных профессиональных метода решения этой задачи в платформе «1С:Предприятие 8».
Среди разработчиков, особенно начинающих, популярна идея проверять тип объекта по наличию у него уникальных системных реквизитов. Например, если у объекта есть реквизит Проведен — значит, это документ. Если есть реквизит Код — значит, это справочник. В запросе это пытаются реализовать через проверку на NULL при неявном соединении.
Давайте проанализируем, почему этот подход категорически не рекомендуется использовать в реальных задачах:
РеквизитСоставногоТипа.Проведен, платформа 1С на уровне СУБД генерирует левое соединение (LEFT JOIN) со всеми таблицами, которые входят в этот составной тип. Если тип данных включает 50 документов, СУБД выполнит 50 соединений! Это приведет к колоссальному падению скорости выполнения запроса и избыточной нагрузке на сервер.Проведен вернет ложное значение. С другой стороны, справочники могут не иметь кода (длина кода установлена в 0), а документы, наоборот, могут содержать реквизит Код или другие схожие по наименованию поля.Перейдем к правильным, протестированным и безопасным методам решения этой задачи.
Этот метод основан на использовании штатной функции запроса ТИПЗНАЧЕНИЯ() и проверке вхождения типа в подготовленный массив. Вместо того чтобы вручную перебирать все метаданные циклом, мы воспользуемся встроенным методом платформы ТипВсеСсылки(), который работает мгновенно.
Рассмотрим пример реализации на встроенном языке 1С:
// 1. Формируем массивы типов для документов и справочников
МассивТиповДокументов = Документы.ТипВсеСсылки().Типы();
МассивТиповСправочников = Справочники.ТипВсеСсылки().Типы();
// 2. Создаем и настраиваем запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Взаиморасчеты.Регистратор КАК Регистратор,
| ВЫБОР
| КОГДА ТИПЗНАЧЕНИЯ(Взаиморасчеты.Регистратор) В (&ТипыДокументов)
| ТОГДА ""Документ""
| КОГДА ТИПЗНАЧЕНИЯ(Взаиморасчеты.Регистратор) В (&ТипыСправочников)
| ТОГДА ""Справочник""
| ИНАЧЕ ""Другой тип""
| КОНЕЦ КАК КлассОбъекта
|ИЗ
| РегистрНакопления.Взаиморасчеты КАК Взаиморасчеты";
Запрос.УстановитьПараметр("ТипыДокументов", МассивТиповДокументов);
Запрос.УстановитьПараметр("ТипыСправочников", МассивТиповСправочников);
РезультатЗапроса = Запрос.Выполнить();
Преимущества метода: Работает быстро, не создает лишних тяжелых соединений на уровне СУБД, код легко читать и поддерживать.
Если нам необходимо жестко зафиксировать проверку типов внутри самого SQL-запроса без использования динамических параметров-массивов, мы можем сгенерировать текст конструкции ВЫБОР КОГДА ... ССЫЛКА ... программно перед выполнением запроса.
Давайте посмотрим на пример реализации такого генератора текста:
// Инициализируем массив для накопления условий
УсловияЗапроса = Новый Массив;
// Пробегаем по метаданным всех документов конфигурации
Для Каждого МетаДокумент Из Метаданные.Документы Цикл
УсловияЗапроса.Добавить("КОГДА Источник.СсылкаСоставногоТипа ССЫЛКА Документ." + МетаДокумент.Имя + " ТОГДА ИСТИНА");
КонецЦикла;
// Объединяем полученные строки в единый блок условий
СтрокаУсловий = СтрСоединить(УсловияЗапроса, Символы.ПС);
// Формируем итоговый текст запроса
ТекстЗапроса =
"ВЫБРАТЬ
| Источник.СсылкаСоставногоТипа КАК Объект,
| ВЫБОР
| " + СтрокаУсловий + "
| ИНАЧЕ ЛОЖЬ
| КОНЕЦ КАК ЭтоДокумент
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК Источник";
Запрос = Новый Запрос(ТекстЗапроса);
Выборка = Запрос.Выполнить().Выбрать();
Преимущества метода: Полученный запрос является абсолютно «чистым» для СУБД, так как оператор ССЫЛКА транслируется платформой в максимально эффективные и быстрые проверки внутренних идентификаторов таблиц.
Если вы разрабатываете отчет в Системе компоновки данных (СКД) или пишете сложный пакетный запрос, где крайне нежелательно использовать программную установку параметров или динамическую сборку текста, можно использовать возможности Библиотеки стандартных подсистем (БСП).
В современных конфигурациях 1С присутствует системный справочник ИдентификаторыОбъектовМетаданных. Он хранит структуру всех объектов метаданных вашей базы в виде иерархического дерева. Мы можем использовать левое соединение с этим справочником по типу пустой ссылки.
Проанализируем пример такого запроса:
ВЫБРАТЬ
Продажи.ДокументОснование КАК Объект,
ВЫБОР
КОГДА МетаданныеИдентификаторы.Родитель.Имя = "Документы"
ТОГДА "Документ"
КОГДА МетаданныеИдентификаторы.Родитель.Имя = "Справочники"
ТОГДА "Справочник"
ИНАЧЕ "Прочий класс метаданных"
КОНЕЦ КАК КлассОбъекта
ИЗ
РегистрНакопления.ВыручкаИСебестоимостьПродаж КАК Продажи
// Соединяем таблицу по типу значения пустой ссылки
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК МетаданныеИдентификаторы
ПО ТИПЗНАЧЕНИЯ(Продажи.ДокументОснование) = ТИПЗНАЧЕНИЯ(МетаданныеИдентификаторы.ЗначениеПустойСсылки)
Важное примечание: Справочник ИдентификаторыОбъектовМетаданных должен быть заполнен актуальными данными. Обычно обновление этого справочника происходит автоматически при обновлении версии конфигурации или при первом запуске предприятия.
Преимущества метода: Запрос выполняется на 100% на стороне СУБД, не требует написания кода на встроенном языке, идеально подходит для сложных аналитических отчетов и схем компоновки данных (СКД).
Для выбора оптимального решения вашей задачи воспользуйтесь следующими рекомендациями:
ТипВсеСсылки().Типы(). Это самый простой и лаконичный код.ССЫЛКА из Способа №2.