Блог Горошко Андрея 1C-Битрикс Использование Bitrix\Main\ORM\Query\Query для построения сложных запросов к Highload-блокам

Использование Bitrix\Main\ORM\Query\Query для построения сложных запросов к Highload-блокам

Средний рейтинг
Еще нет оценок

Highload-блоки в Битрикс — это эффективный инструмент для работы с крупными объемами данных, значительно превосходящий стандартные инфоблоки по производительности, особенно в условиях высоких нагрузок. Они оптимизированы для хранения и обработки больших объемов информации, используя подход, схожий с NoSQL-хранилищами. Взаимодействие с данными Highload-блоков осуществляется через объектно-ориентированные модели (ORM), что позволяет выполнять операции создания, чтения, обновления и удаления (CRUD) с помощью объектных методов.

Класс Bitrix\Main\ORM\Query\Query в рамках ORM Битрикс D7 предоставляет мощные возможности для построения сложных запросов к данным, включая Highload-блоки, обеспечивая гибкость и контроль над формированием SQL-запросов.

Для построения сложных запросов к Highload-блокам с использованием Bitrix\Main\ORM\Query\Query необходимо выполнить несколько ключевых шагов.

1. Подключение модуля Highload-блоков

Перед началом работы с Highload-блоками через D7 API обязательно подключите модуль highloadblock.

<?php
use Bitrix\Main\Loader;
use Bitrix\Highloadblock as HL;
use Bitrix\Main\Entity;
use Bitrix\Main\ORM\Query\Query;

Loader::includeModule("highloadblock");
?>

2. Получение сущности Highload-блока

Каждый Highload-блок представляет собой уникальную сущность, с которой работает ORM. Для получения этой сущности требуется знать ID или название Highload-блока.

<?php
$hlBlockId = 1; // Замените на ID вашего Highload-блока
$hlblock = HL\HighloadBlockTable::getById($hlBlockId)->fetch();

if (!$hlblock) {
    throw new \Exception("Highload-блок с ID " . $hlBlockId . " не найден.");
}

$entity = HL\HighloadBlockTable::compileEntity($hlblock);
$dataClass = $entity->getDataClass();
?>

3. Создание объекта Query и построение запроса

После получения класса DataManager для Highload-блока можно приступать к формированию запросов. Несмотря на то, что метод getList() широко используется, Bitrix\Main\ORM\Query\Query предоставляет более широкие возможности для конструирования сложных запросов.

Примеры построения сложных запросов:

Выборка с фильтрацией, сортировкой и ограничением

Методы setSelect() для указания выбираемых полей, setFilter() для фильтрации данных, setOrder() для сортировки и setLimit() для ограничения количества записей являются основными при работе с классом Query.

<?php
$query = new Query($entity);
$query->setSelect(['ID', 'UF_NAME', 'UF_VALUE']); // Выбираем поля ID, UF_NAME, UF_VALUE
$query->setFilter([
    '=UF_CATEGORY' => 10, // Фильтр по UF_CATEGORY, равный 10
    '>UF_PRICE' => 1000  // Фильтр по UF_PRICE, больше 1000
]);
$query->setOrder(['UF_NAME' => 'ASC']); // Сортировка по UF_NAME по возрастанию
$query->setLimit(10); // Ограничение на 10 записей

$result = $query->exec();
while ($row = $result->fetch()) {
    print_r($row);
}
?>

Использование логических операторов в фильтре

Условия в фильтре можно комбинировать с помощью логического оператора LOGIC (OR или AND).

<?php
$query = new Query($entity);
$query->setSelect(['ID', 'UF_PRODUCT_NAME']);
$query->setFilter([
    'LOGIC' => 'OR',
    ['=UF_STATUS' => 'active'],
    ['=UF_STATUS' => 'pending', '>UF_DATE_CREATED' => '2025-01-01']
]);
$result = $query->exec();
while ($row = $result->fetch()) {
    print_r($row);
}
?>

Объединение таблиц (JOIN)

Для связывания Highload-блоков с другими сущностями (например, инфоблоками или другими Highload-блоками) используется динамическая регистрация полей через registerRuntimeField с типом ReferenceField. Класс Bitrix\Main\ORM\Query\Join предоставляет методы для определения условий объединения, например, on().

<?php
use Bitrix\Main\Entity\ReferenceField;
use Bitrix\Iblock\ElementTable; // Пример для инфоблоков

$query = new Query($entity);
$query->setSelect([
    'ID',
    'UF_ELEMENT_ID',
    'ELEMENT_NAME' => 'ELEMENT.NAME', // Выбираем название элемента из связанной сущности
]);
$query->registerRuntimeField(
    'ELEMENT',
    new ReferenceField(
        'ELEMENT',
        ElementTable::class, // Класс сущности, с которой связываем
        ['=this.UF_ELEMENT_ID' => 'ref.ID'], // Условие связи (this - текущий HL-блок, ref - связанная сущность)
        ['join_type' => 'inner'] // Тип JOIN (inner, left, right)
    )
);
$query->setFilter(['=ELEMENT.IBLOCK_ID' => 5]); // Фильтр по ID инфоблока
$result = $query->exec();
while ($row = $result->fetch()) {
    print_r($row);
}
?>

Группировка и агрегатные функции

Возможность группировки данных с помощью setGroup() и выполнения агрегатных функций (таких как COUNTAVGSUMMAXMIN) через Entity\ExpressionField в setSelect() значительно расширяет функционал запросов.

<?php
$query = new Query($entity);
$query->setSelect([
    'UF_CATEGORY',
    new Entity\ExpressionField('COUNT_ITEMS', 'COUNT(%s)', 'ID'), // Подсчет элементов
    new Entity\ExpressionField('AVG_PRICE', 'AVG(%s)', 'UF_PRICE') // Средняя цена
]);
$query->setGroup(['UF_CATEGORY']);
$result = $query->exec();
while ($row = $result->fetch()) {
    print_r($row);
}
?>

Runtime-поля (runtime section) в Query или getList позволяют динамически регистрировать новые поля для конкретного запроса. Это могут быть ExpressionField для вычислений или поля других типов, что фактически расширяет карту сущности на время выполнения запроса и особенно полезно для объединения данных из различных Highload-блоков без изменения их оригинальных ORM-моделей.

Важные моменты и лучшие практики при работе с ORM и Highload-блоками

  • Явное указание полей: Всегда явно указывайте поля в setSelect(). Это позволяет избежать избыточной выборки данных, что положительно сказывается на производительности.
  • Использование операторов: Для точного соответствия используйте оператор =. Отсутствие явного оператора может привести к использованию LIKE Битриксом по умолчанию, что замедляет запросы.
  • Множественные поля: Работа с полями типа «множественное» требует особого внимания, так как они могут храниться в сериализованном виде или в отдельных таблицах. Учитывайте это при построении запросов.
  • Отслеживание запросов: Для отладки и оптимизации используйте Application::getConnection()->startTracker() и getTrackerQuery()->getSql() для просмотра сгенерированного SQL-запроса. Это помогает понять, какой именно SQL-запрос выполняется.
  • Производительность и кэширование: Хотя Highload-блоки созданы для высоких нагрузок, при очень больших объемах данных может потребоваться дополнительная оптимизация базы данных (индексация) и кэширование. ORM Битрикс поддерживает кэширование запросов с параметром ttl (time to live), включая запросы с JOIN’ами. Кэш автоматически сбрасывается при операциях addupdatedelete и может быть очищен вручную через cleanCache() для сущности.
  • Обработчики событий Highload-блоков: Highload-блоки поддерживают различные события (OnBeforeAddOnAfterAddOnBeforeUpdateOnAfterUpdateOnBeforeDeleteOnAfterDelete). Эти события позволяют внедрять пользовательскую логику до или после операций изменения данных, что дает возможности для валидации, модификации данных или выполнения дополнительных действий.
  • Структура класса Query: Класс Bitrix\Main\ORM\Query\Query содержит множество защищенных методов (buildSelect()buildJoin()buildWhere()buildGroup()buildHaving()buildOrder()), которые отвечают за построение соответствующих частей SQL-запроса, а также управляет внутренними цепочками для различных условий запроса. Понимание их предназначения может быть полезно для глубокой отладки.

Использование Bitrix\Main\ORM\Query\Query с Highload-блоками обеспечивает мощный и гибкий инструмент для работы с данными, позволяя эффективно строить даже самые сложные запросы.

Мой рейтинг:

Добавить комментарий

Related Post

Создание собственных D7 ORM сущностей (таблиц) в Битрикс: Пошаговое руководствоСоздание собственных D7 ORM сущностей (таблиц) в Битрикс: Пошаговое руководство

Средний рейтинг Еще нет оценок Работать с готовыми ORM-сущностями вроде ElementTable — это хорошо, но настоящая сила D7 ORM раскрывается, когда вы создаете собственные таблицы для хранения данных вашего модуля. Давайте создадим

1с Битрикс фильтрация по свойству элементов1с Битрикс фильтрация по свойству элементов

Средний рейтинг Еще нет оценок В Битриксе вы можете использовать различные условия выборки с помощью фильтрации в параметре 'filter' при вызове метода getList() или других методов выборки данных. Вот несколько

Сложные фильтры в D7 ORM: Query::filter() для логики И/ИЛИ и вложенных условийСложные фильтры в D7 ORM: Query::filter() для логики И/ИЛИ и вложенных условий

Средний рейтинг Еще нет оценок Простой массив в параметре filter метода getList() отлично подходит для условий, объединенных по логике «И» (AND). Но что делать, если нужна более сложная логика, например, (A AND B) OR C?