Блог Горошко Андрея 1C-Битрикс Отношение Многие-ко-Многим (N:M) в D7 ORM: Реализация через промежуточную таблицу

Отношение Многие-ко-Многим (N:M) в D7 ORM: Реализация через промежуточную таблицу

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

Классическая задача: у одной Статьи может быть много Тэгов, и один Тэг может быть привязан к многим Статьям. В реляционных базах данных это решается через промежуточную таблицу.

Структура таблиц

  1. b_article (ID, NAME) — Статьи.
  2. b_tag (ID, NAME) — Тэги.
  3. b_article_tag (ARTICLE_ID, TAG_ID) — Промежуточная таблица.

Шаг 1: Создание сущностей

Сущности для Статей и Тэгов стандартные. Интерес представляет промежуточная сущность ArticleTagTable.

namespace My\Module;

use Bitrix\Main\Entity;

class ArticleTagTable extends Entity\DataManager
{
    public static function getTableName()
    {
        return 'b_article_tag';
    }

    public static function getMap()
    {
        return [
            // Поле ID статьи
            new Entity\IntegerField('ARTICLE_ID', [
                'primary' => true
            ]),
            
            // Связь со статьей
            new Entity\ReferenceField(
                'ARTICLE',
                '\My\Module\ArticleTable',
                ['=this.ARTICLE_ID' => 'ref.ID']
            ),

            // Поле ID тега
            new Entity\IntegerField('TAG_ID', [
                'primary' => true
            ]),

            // Связь с тегом
            new Entity\ReferenceField(
                'TAG',
                '\My\Module\TagTable',
                ['=this.TAG_ID' => 'ref.ID']
            ),
        ];
    }
}

Шаг 2: Добавление связей в основные сущности

Чтобы удобно выбирать тэги из статьи, добавим связь «Один-ко-Многим» в ArticleTable.

// В ArticleTable::getMap()
new Entity\ReferenceField(
    'TAG_RELATION', // Виртуальное поле связи
    '\My\Module\ArticleTagTable', // Промежуточная таблица
    ['=this.ID' => 'ref.ARTICLE_ID']
),

Шаг 3: Выборка (Получить статьи с их тегами)

Это самое интересное. Чтобы получить названия тегов, нам нужно пройти через две связи: Article -> ArticleTag -> Tag.

$articles = \My\Module\ArticleTable::getList([
    'select' => [
        'ID', 
        'NAME',
        'TAG_NAME' => 'TAG_RELATION.TAG.NAME' // Двойной переход!
    ]
])->fetchCollection();

foreach ($articles as $article) {
    // Внимание: из-за JOIN это вернет декартово произведение.
    // Если у статьи 3 тега, будет 3 строки в выборке с одинаковым ID статьи.
    // D7 Collection умеет это "склеивать" (см. статью про Коллекции).
}

Оптимизированный подход (раздельные запросы):
Лучше выбрать статьи, собрать их ID, а потом отдельным запросом выбрать все теги для этих статей через ArticleTagTable.

// 1. Получаем статьи
$articles = ArticleTable::getList(...)->fetchAll();
$articleIds = array_column($articles, 'ID');

// 2. Получаем теги
$tags = ArticleTagTable::getList([
    'select' => ['ARTICLE_ID', 'TAG_NAME' => 'TAG.NAME'],
    'filter' => ['@ARTICLE_ID' => $articleIds]
])->fetchAll();

// 3. Собираем в PHP

Вывод:
Связь N:M в D7 реализуется явно через сущность промежуточной таблицы. Хотя D7 позволяет строить цепочки TAG_RELATION.TAG.NAME в одном запросе, для производительности часто лучше разбивать это на два простых запроса или использовать метод QueryHelper::decompose .

Многие ко многим D7, ManyToMany Bitrix, промежуточная таблица ORM, связи ORM, ReferenceField, getList N:M.

Мой рейтинг:

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

Related Post

Добавление и обновление элементов в Битрикс: CIBlockElement::Add и UpdateДобавление и обновление элементов в Битрикс: CIBlockElement::Add и Update

Средний рейтинг Еще нет оценок Создание и редактирование контента — базовые операции для любого сайта. В 1С-Битрикс за это отвечают методы CIBlockElement::Add и CIBlockElement::Update. Они являются частью старого API, но до сих пор

 Безопасность AJAX-компонентов: Подписанные параметры (SignedParameters) Безопасность AJAX-компонентов: Подписанные параметры (SignedParameters)

Средний рейтинг Еще нет оценок Когда вы делаете компонент асинхронным (AJAX), его параметры ($arParams) становятся уязвимы. Злоумышленник может изменить их прямо в JavaScript-коде перед отправкой запроса. Например, подменить IBLOCK_ID и получить доступ

Валидация данных в D7 ORM: Встроенные и кастомные валидаторыВалидация данных в D7 ORM: Встроенные и кастомные валидаторы

Средний рейтинг Еще нет оценок Валидация — это процесс проверки данных на корректность перед их сохранением. D7 ORM предоставляет мощный механизм валидаторов, который описывается прямо в getMap() вашей сущности. Это позволяет держать