ORM Bitrix — это слой объектно-реляционного отображения в ядре D7. Он описывает таблицы классами-наследниками DataManager, а выборки строит через объект Query, скрывая ручной SQL за типизированным API.
Что такое ORM в Битрикс
ORM в 1С-Битрикс появилась вместе с ядром D7 и живёт в пространстве имён Bitrix\Main\ORM. Её задача — представить строку таблицы БД как набор типизированных полей, а операции чтения и записи — как методы объекта. Разработчик описывает структуру таблицы один раз в Table-классе, а дальше работает с ней через единый интерфейс.
В отличие от «классических» ORM вроде Doctrine, битриксовая реализация не строит полноценные Entity-объекты для каждой строки по умолчанию. Базовый режим — работа с массивами, но при этом доступны объекты, коллекции и связи. Это компромисс между удобством и производительностью на больших выборках.
| Понятие ORM | Класс ядра | Роль |
|---|---|---|
| Описание таблицы | Entity\DataManager | Схема полей и CRUD |
| Метаданные | ORM\Entity | Скомпилированное описание сущности |
| Запрос | ORM\Query\Query | Построитель выборки |
| Результат | ORM\Query\Result | Итерируемый набор строк |
DataManager и Table-класс
Каждая таблица описывается классом, унаследованным от Bitrix\Main\ORM\Data\DataManager. Минимум, что требуется реализовать, — методы getTableName() и getMap(). Первый возвращает имя таблицы в БД, второй — карту полей.
namespace Vendor\Catalog;
use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\ORM\Fields\IntegerField;
use Bitrix\Main\ORM\Fields\StringField;
class BrandTable extends DataManager
{
public static function getTableName(): string
{
return 'vendor_catalog_brand';
}
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new StringField('CODE', ['required' => true]),
new StringField('NAME'),
];
}
}Класс сразу получает готовые статические методы: getList(), getById(), add(), update(), delete(). Ничего дополнительно писать не нужно — CRUD доступен из коробки.
Базовые операции: add, update, delete
Операции записи возвращают объект Result. Его обязательно проверять через isSuccess() — исключение при ошибке валидации по умолчанию не бросается, но ошибки копятся в результате.
use Vendor\Catalog\BrandTable;
$result = BrandTable::add([
'CODE' => 'acme',
'NAME' => 'ACME',
]);
if ($result->isSuccess()) {
$id = $result->getId();
} else {
$errors = $result->getErrorMessages();
}
BrandTable::update($id, ['NAME' => 'ACME Corp']);
BrandTable::delete($id);add()принимает ассоциативный массив полей и возвращаетAddResultсgetId();update()первым аргументом принимает первичный ключ (или массив ключей для составного PK);delete()удаляет по первичному ключу;- валидаторы и обязательность полей проверяются автоматически перед записью.
Объект Query и getList
Основной способ чтения — метод getList(), который принимает массив параметров и возвращает объект Result. Под капотом он собирает объект Query и генерирует SQL.
$result = BrandTable::getList([
'select' => ['ID', 'NAME', 'CODE'],
'filter' => ['=CODE' => 'acme', '>ID' => 0],
'order' => ['NAME' => 'ASC'],
'limit' => 20,
'offset' => 0,
]);
while ($row = $result->fetch()) {
echo $row['NAME'];
}
$all = $result->fetchAll();Ключи фильтра поддерживают операторы-префиксы: = (точное), % (LIKE), >, <, >=, ! (не равно). Массив в значении превращается в IN. Для сложной логики используется класс Bitrix\Main\ORM\Query\Filter\ConditionTree.
Объектная модель: Object и Collection
Кроме массивов ORM умеет возвращать полноценные объекты. Метод fetchObject() отдаёт EntityObject, а fetchCollection() — коллекцию. К полям обращаются через геттеры вида get('NAME') или магические getName().
$brand = BrandTable::getByPrimary(1)->fetchObject();
$brand->setName('New name');
$brand->save(); // UPDATE только изменённых полей
$collection = BrandTable::getList()->fetchCollection();
foreach ($collection as $item) {
echo $item->getCode();
}referenceField автоматически подгружает связанную сущность. На больших выборках объекты дороже массивов по памяти — выбирайте режим под задачу.Runtime-поля и агрегаты
ORM позволяет добавлять вычисляемые поля прямо в запросе — через ключ runtime. Это удобно для агрегатов (COUNT, SUM) и выражений без изменения Table-класса.
use Bitrix\Main\ORM\Fields\ExpressionField;
$result = OrderTable::getList([
'select' => ['STATUS', 'CNT'],
'runtime' => [
new ExpressionField('CNT', 'COUNT(*)'),
],
'group' => ['STATUS'],
]);Через runtime также объявляют временные связи, которых нет в getMap(). Это делает выборки гибкими: одна и та же сущность может участвовать в разных JOIN в зависимости от контекста запроса.
Когда использовать ORM, а когда нет
ORM — предпочтительный способ работы с данными в новом коде, но не универсальный молоток.
- Стоит: собственные таблицы модулей, Highload-блоки, сервисный код, где важна читаемость и типобезопасность.
- Осторожно: тяжёлые аналитические запросы с нестандартным SQL — иногда прямой запрос через
Application::getConnection()честнее и быстрее. - Учитывайте: инфоблоки исторически имеют свой API (
CIBlockElement), хотя ORM инфоблоков тоже существует.
$query->getQuery() возвращает готовый текст запроса — используйте его для профилирования.Итог
ORM Bitrix описывает таблицы Table-классами на базе DataManager, даёт готовый CRUD, строит выборки через getList() и объект Query, поддерживает объектный режим, runtime-поля и связи. Это основной инструмент работы с данными в ядре D7 — и знать его должен каждый разработчик на платформе.
Мы в B2Bsite строим на ORM модули обмена, каталоги и B2B-логику: аккуратные сущности, предсказуемые запросы и контролируемый SQL. Если нужна интеграция или собственный модуль обмена данными на прочной модели — поможем спроектировать и реализовать.
Частые вопросы
Что такое DataManager в Битрикс?
Это базовый класс ORM (Bitrix\Main\ORM\Data\DataManager), от которого наследуют Table-классы. Он даёт готовые методы getList, getById, add, update, delete после описания getTableName и getMap.
Как сделать выборку через ORM?
Через статический метод getList таблицы с параметрами select, filter, order, limit. Он возвращает объект Result, из которого строки достают методом fetch или fetchAll.
Нужно ли проверять результат add и update?
Да. Эти методы возвращают объект Result, который надо проверять через isSuccess. По умолчанию ошибки валидации не бросают исключение, а накапливаются в результате.
Чем fetchObject отличается от fetch?
fetch возвращает строку как ассоциативный массив, а fetchObject — объект EntityObject с геттерами и сеттерами. Объектный режим удобнее для доменной логики и связей, но дороже по памяти.
Что такое runtime-поля?
Это вычисляемые поля и временные связи, объявляемые прямо в запросе через ключ runtime, без изменения Table-класса. Их применяют для агрегатов COUNT, SUM и разовых JOIN.
Какие операторы поддерживает фильтр getList?
Префиксы =, %, >, <, >=, <=, ! перед именем поля. Массив в значении превращается в IN. Для сложной логики используется ConditionTree.
Можно ли посмотреть сгенерированный SQL?
Да, объект Query имеет метод getQuery, возвращающий текст запроса. Это помогает профилировать тяжёлые выборки и находить неоптимальные JOIN.
Поможем с настройкой и поддержкой Для разработчиков
Поможем с настройкой, доработкой и поддержкой Для разработчиков.