В чем разница между inversedBy и mappedBy?

Я разрабатываю свое приложение, используя Zend Framework 2 и Doctrine 2.

При написании аннотаций я не могу понять разницу между mappedBy и inversedBy.

Когда мне следует использовать mappedBy?

Когда мне следует использовать inversedBy?

Когда я не должен использовать ни?

Вот пример:

 /**
 *
 * @ORM\OneToOne(targetEntity="\custMod\Entity\Person", mappedBy="customer")
 * @ORM\JoinColumn(name="personID", referencedColumnName="id")
 */
protected $person;

/**
 *
 * @ORM\OneToOne(targetEntity="\Auth\Entity\User")
 * @ORM\JoinColumn(name="userID", referencedColumnName="id")
 */
protected $user;

/**
 *
 * @ORM\ManyToOne (targetEntity="\custMod\Entity\Company", inversedBy="customer")
 * @ORM\JoinColumn (name="companyID", referencedColumnName="id")
 */
protected $company;

Я сделал быстрый поиск и нашел следующее, но я все еще смущен:

Ответ 1

  • mappedBy должен быть указан на обратной стороне ассоциации (двунаправленной)
  • inversedBy должен быть указан на стороне пользователя (двунаправленной) ассоциации

из документации доктрины:

  • ManyToOne всегда является областью поддержки двунаправленной связи.
  • OneToMany всегда является обратной стороной двунаправленной связи.
  • Собственной стороной OneToOne является сущность с таблицей, содержащей внешний ключ.

См. http://docs.doctrine-project.org/en/latest/reference/unitofwork-associations.html

Ответ 2

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

inversedBy и mappedBy используются двигателем INTERNAL DOCTRINE для сокращения количества SQL-запросов, необходимых для получения необходимой вам информации. Чтобы быть ясным, если вы не добавляете inversedBy или mappedBy, ваш код будет работать, но не будет оптимизирован.

Итак, например, посмотрите на следующие классы:

class Task
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="task", type="string", length=255)
     */
    private $task;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="dueDate", type="datetime")
     */
    private $dueDate;

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="tasks", cascade={"persist"})
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     */
    protected $category;
}

class Category
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="Task", mappedBy="category")
     */
    protected $tasks;
}

Эти классы, если вы должны были запустить команду для создания схемы (например, bin/console doctrine:schema:update --force --dump-sql), вы заметите, что в таблице категорий нет столбца для нее. (это потому, что на нем нет аннотации столбца)

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

Как и мудрый, в классе "Задачи" свойство $category упоминает, что оно инвертированоBy = "задачи", обратите внимание, что это множественное число, это НЕ ПЛОХАЛЬНОЕ НАЗВАНИЕ КЛАССА, а только потому, что свойство называется "protected $tasks" в классе Category.

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

Сторона, которая ссылается на внешний ключ, такой как "задачи" в моем примере, всегда получает атрибут inversedBy, потому что ему нужно знать, какой класс (через команду targetEntity) и какую переменную (inversedBy =) для этого класса "работать назад" 'так сказать и получить информацию о категории. Легкий способ запомнить это, это класс, который будет иметь foreignkey_id, который должен иметь inversedBy.

Здесь, как и в случае с категорией и свойством $tasks (которое не входит в таблицу, только часть класса для целей оптимизации) является MappedBy 'tasks', это создает отношения между двумя объектами, так что доктрина теперь могут безопасно использовать JOIN SQL-инструкции вместо двух отдельных операторов SELECT. Без mappedBy механизм doctrine не будет знать из инструкции JOIN, что он создаст какую переменную в классе "Задача" для размещения информации о категории.

Надеюсь, это объяснит это немного лучше.

Ответ 3

В двунаправленном отношении есть как сторона-обладатель, так и обратная сторона

mappedBy: положите в обратную сторону двунаправленного отношения. Чтобы ссылаться на свою сторону

inversedBy: положите в Собственную сторону двунаправленного отношения Чтобы ссылаться на свою обратную сторону

И

атрибут mappedBy, используемый с объявлением отображения OneToOne, OneToMany или ManyToMany.

inversedBy, используемый с объявлением отображения OneToOne, ManyToOne или ManyToMany.

Уведомление: Собственная сторона двунаправленного отношения сторона, которая содержит внешний ключ.

есть две ссылки о inversedBy и mappedBy в Doctrine Documentation: Первая ссылка, Вторая ссылка

Ответ 4

5.9.1. Собственная и обратная сторона

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

Возьмем пример двух объектов Article и Tag. Всякий раз, когда вы хотите связать статью с тегом и наоборот, в основном эта статья несет ответственность за это отношение. Всякий раз, когда вы добавляете новую статью, вы хотите связать ее с существующими или новыми тегами. Форма "Создать статью", вероятно, поддерживает это понятие и позволяет напрямую указывать теги. Вот почему вы должны выбрать статью как собственную сторону, так как она делает код более понятным:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html