Symfony2/Doctrine отображает суперкласс в середине наследования таблицы классов

В настоящее время я имею структуру модели следующим образом:

/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="related_type", type="string")
 * @ORM\DiscriminatorMap({"type_one"="TypeOne", "type_two"="TypeTwo"})
 */
abstract class BaseEntity {

    ... (all the usual stuff, IDs, etc)

    /**
     * @ORM\OneToMany(targetEntity="Comment", mappedBy="baseEntity")
     */
    private $comments;
}

/**
 * @ORM\Entity
 */
class TypeOne extends BaseEntity {
    /**
     * @ORM\Column(type="string")
     */
    private $name;

    /**
     * @ORM\Column(type="string")
     */
    private $description;
}

/**
 * @ORM\Entity
 */
class TypeTwo extends BaseEntity {
    /**
     * @ORM\Column(type="string")
     */
    private $name;

    /**
     * @ORM\Column(type="string")
     */
    private $description;   
}

/**
 * @ORM\Entity
 */
class Comment {

    ... (all the usual stuff, IDs, etc)

    /**
     * @ORM\ManyToOne(targetEntity="BaseEntity", inversedBy="comments")
     */
    private $baseEntity;
}

Идея здесь заключается в том, чтобы связать комментарий с любой из других таблиц. Кажется, что все работает нормально (предоставлено, я все еще изучаю варианты дизайна, поэтому может быть лучший способ сделать это...), но я заметил, что в подклассах есть некоторые общие поля что я хотел бы перейти в общий родительский класс. Я не хочу переместить их в BaseEntity, так как будут другие объекты, которые являются дочерними элементами BaseEntity, но у них не будет этих полей.

Я рассмотрел создание родительского класса MappedSuperclass посередине, например:

/**
 * @ORM\MappedSuperclass
 */
abstract class Common extends BaseEntity {
    /**
     * @ORM\Column(type="string")
     */
    private $name;

    /**
     * @ORM\Column(type="string")
     */
    private $description;       
}

/**
 * @ORM\Entity
 */
class TypeOne extends Common {}

/**
 * @ORM\Entity
 */
class TypeTwo extends Common {}

Я решил, что это сработает, но генератор схемы базы данных доктрины жалуется, что я не могу сопоставить OneToMany в MappedSuperclass. Я не ожидал, что это будет проблемой, поскольку отображение OneToMany все еще находится между корневой базой BaseEntity и комментарием. Есть ли другая структура, которую я должен использовать, или другой способ сделать эти поля общими, не добавляя их в BaseEntity?

Ответ 1

Из Документов:

Отображенный суперкласс является абстрактным или конкретным классом, который обеспечивает постоянное состояние объекта и картографическую информацию для своих подклассов, , но который сам по себе не является сущностью. Как правило, цель такого сопоставленный суперкласс состоит в том, чтобы определить информацию состояния и отображения, которая общий для нескольких классов сущностей.

Тем не менее, как вы можете связать одну сущность с той, которая не является?

Больше из документов:

Отображаемый суперкласс не может быть сущностью, не доступен для запроса и постоянные отношения, определяемые сопоставленным суперклассом, должны быть однонаправленный (только с собственной стороной). Это означает, что один-ко-многим привязки вообще невозможно в отображаемом суперклассе.Кроме того, ассоциации "многие-ко-многим" возможны только в том случае, если сопоставленные Суперкласс используется только в одном объекте на данный момент. Для дальнейшая поддержка наследования, однократное или объединенное наследование таблицы функции должны быть использованы.

Источник: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html


Обновление

Поскольку ваш MappedSuperClass расширяет BaseEntity, он также наследует ассоциации BaseEntity, как если бы он был собственным. Таким образом, вы эффективно имеете OneToMany на MappedSuperClass.

Чтобы обойти это, вам нужно будет изменить/расширить доктрину, чтобы работать так, как вы хотите.

Что касается встроенных функций, у вас есть два варианта:

Наследование таблицы классов Вы Общий класс и результирующее представление БД имели бы общие поля, а дочерние классы теперь будут иметь только поля, специфичные для самих себя. К сожалению, это может быть искажение ваших данных, если вы просто пытаетесь сгруппировать общие поля для их группировки.

Сделать общий объект Похоже, что все Mapped Super Class являются сущностью, которая не представлена ​​в БД. Итак, сделайте обычную сущность. Недостатком является то, что вы получите таблицу DB, но вы можете просто удалить ее.

Я рекомендую вам взглянуть на ваши данные и убедиться, что вы только группируете поля, если они являются общими как по имени, так и по назначению. Например, ComputerBox, ShoeBox, Man и Woman могут иметь свойство "height", но в этом случае я бы не предложил иметь общий класс с свойством "height", которым все они наследуются. Вместо этого у меня была бы коробка с полями, общие для ComputerBox и ShoeBox, и у меня был бы человек с полями, общие для человека и женщины. В этой ситуации наследование класса или отдельная таблица, если вы предпочитаете, будут работать отлично.

Если ваши данные следуют этому примеру, перейдите в "Одиночная таблица" или "Наследование классов". Если нет, я бы посоветовал не группировать поля.