Как удаляются связи OneToMany и ManyToMany в D7 ORM

06.04.2026

Проблема/контекст

В D7-связях удаление часто понимают слишком упрощенно: если сущности связаны, значит ядро само "разрулит" каскад. Но в исходниках ORM поведение у OneToMany и ManyToMany принципиально разное, и ошибка в ожиданиях быстро приводит либо к лишнему удалению, либо к зависшим данным.

Ключевая точка здесь Bitrix\Main\ORM\Objectify\EntityObject::delete(). Для OneToMany метод смотрит на getCascadeDeletePolicy() и либо удаляет дочерние объекты, либо снимает ссылку через sysRemoveAllFromCollection(). Для ManyToMany логика иная: при удалении объекта ядро всегда очищает таблицу-посредник, а сами связанные сущности не удаляет. Это напрямую следует из связки EntityObject::delete(), sysRemoveAllFromCollection() и sysSaveRelations().

Решение с кодом

Если дочерняя запись принадлежит только одному владельцу, используйте OneToMany и явно задавайте политику удаления:

        <?php
use Bitrix\Main\ORM\Fields\Relations\CascadePolicy;
use Bitrix\Main\ORM\Fields\Relations\OneToMany;

final class OrderTable extends \Bitrix\Main\ORM\Data\DataManager
{
    public static function getMap(): array
    {
        return [
            // При удалении заказа удалятся и его позиции
            (new OneToMany('ITEMS', OrderItemTable::class, 'ORDER'))
                ->configureCascadeDeletePolicy(CascadePolicy::FOLLOW),
        ];
    }
}

    

Если FOLLOW не указан, у OneToMany по умолчанию работает SET_NULL: ядро не удаляет дочерние строки, а отвязывает их от родителя. Это удобно для журналов, уведомлений и других записей, которые могут жить дольше основной сущности.

Для общих справочников и тегов используйте ManyToMany, но помните реальное поведение удаления:

        <?php
use Bitrix\Main\ORM\Fields\Relations\ManyToMany;

final class ArticleTable extends \Bitrix\Main\ORM\Data\DataManager
{
    public static function getMap(): array
    {
        return [
            // При удалении статьи ядро очистит только b_article_tag
            (new ManyToMany('TAGS', TagTable::class))
                ->configureTableName('b_article_tag'),
        ];
    }
}

    

После $article->delete() будут удалены строки из b_article_tag, потому что sysSaveRelations() удаляет записи посредника через data class медиаторной сущности. Сами теги останутся. Поэтому ManyToMany подходит там, где связь должна исчезнуть, а партнерская сущность продолжает использоваться в системе. Если же нужно удалять и "осиротевшие" записи, не полагайтесь на ManyToMany: описывайте таблицу связи явно или запускайте отдельный сервис очистки после удаления основной сущности.

Итог

Для OneToMany в D7 важно выбирать политику FOLLOW или SET_NULL осознанно. Для ManyToMany безопасно рассчитывать только на очистку таблицы связей, а не на удаление связанных объектов.

Опубликовано 6 дней назад

Комментарии (0)

Пожалуйста, войдите в аккаунт, чтобы оставить комментарий

Оставить комментарий

Пока нет ни одного комментария. Будьте первым!

Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.

AI Домовой История

0 / 25

Привет! Я помогу с вопросами по 1С-Битрикс.

Спрашивай про D7, ORM, компоненты или события.

Требуется авторизация

Войдите или зарегистрируйтесь, чтобы задавать вопросы AI-ассистенту.

Войти