При разработке модулей или крупного функционала требуется большое количество пользовательских таблиц. Рассмотрим подробнее, как можно организовать взаимосвязь между ними. Для удобной формы организации связей между ними будем использовать DataManager ORM. Для агрегации данных ORM будет использоваться объект Query. Для манипулирования данными будет использоваться Object Entity, так как применение геттерев и сеттером улучшает восприятие кода.
Рассмотрим организацию связей на примере связей таблиц книг и авторов
Для начала в административной части Битрикса на странице SQL запросов создаем таблицу авторов:

Далее создадим таблицу книг:
Для создания связей many to many создадим таблицу authors_books:
Для показательных примеров заполняем базы данных авторов, книг и таблицу связей:

Для работы в системе Битрикс будем использовать orm: описываем через сущность Bitrix\Main\Entity\DataManager
Описание таблицы AuthorsTable со всеми зависимости:


Описание таблицы BooksTable:

На конкретном примере модели данных AuthorsBooksTable будем определять связь many to many посредством референс полей:

Организовывать связи в Битриксе можно на уровне модели таблиц, где в описании через поля Reference связываются сущности связью one-to-one и one-to-many. Для организации связей many-to-many требуется создать вручную таблицу authors_books и описать в модели сущности поля через объект релации ManyToMany. Необязательно описывать поле в обеих сущностях — можно только в одной, но тогда и доступ к данным будет осуществляться только через нее.
Практический пример One To One
Пример связи One To One c использованием query, где у книги получаем автора:
Результат:
string(12) "Виктор"
string(12) "Иванов"
bool(true)
Также более конкретную выборку из object entity можно делать методом get:

Альтернативный вариант через getList реализации связи one to one:

Если мы хотим создать книгу и привязать автора:

Если мы хотим перепривязать книге нового автора:
Для удаления связи книги и автора:
После этого ссылочный ключ author_id получит значение NULL.
Практический пример One to Many
Пример на объекте query:

Результат:
string(35) "История античности"
string(42) "История древнего китая"
На примере показана реализация связи one to many, где мы выбираем автора с айди 1 и получаем все связанные с ним книги, object entity и получаем связанные книги, которые были объявлены в модели через объект OneToMany.
Альтернативный пример через классический getList:

Примеры работы со связями таблицы, если мы хотим у автора удалить все привязки к книгам: у всех отвязанных книг поле author_id, станет null

Практический пример Many to Many
Пример через query, где по идентификатору книги находим всех соавторов. Использование Object entity исключает дубликаты сущностей в отличие от массивов:

Результат:
string(12) "Виктор"
string(35) "История античности"
string(18) "Александр"
string(35) "История античности"
string(12) "Сергей"
string(35) "История античности"
Альтернативный вариант через getList:

Query
Также в query можно динамически создавать поля через метод registerRuntimeField. На примере мы получаем все элементы iblock с подтянутыми динамически секциями, в которых они имеются:

Объект query позволяет проводить агрегацию данных более наглядно, посредством большого количество именованных методов селекторов. Если детально посмотреть все методы объекта query, получится список:
where, whereNot, whereColumn, whereNull, whereIn, whereNotIn ,whereBetween, whereNotBetween, whereLike, whereNotLike, whereExists ,whereNotExists, whereMatch, whereNotMatch , whereExpr
Через логический фильтр Query::filter()->logic('or') или (and) можно создавать вложенные ветвления условий.
Пример агрегации на таблице книги:

Очень удобно применять такие ветвления в конструкции switch. Приводим несколько примеров выборочной агрегации данных:

Также в query существуют методы, которые отсутствуют в других способах получения и агрегации данных в Битрикс. Это методы union и unionAll:

Если происходит частое переиспользование логики агрегации данных, можно создать кастомные методы query через ключевое слово with на модели данных. Таким методом можно получать быстро всех активных авторов:

Также стоит отметить важную особенность о выборке с отношениями:

При вызове fetchCollection сформируется запрос с тяжеловесными джойми, который сильно замедлит работу кода. Для исключения этого в Битриксе существует композитор:

Декомпозитор разбивает sql на простые запросы, тем самым значительно ускоряя вызов.