Яка різниця між перевернутимBy та mappedBy?


102

Я розробляю свою програму за допомогою 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;

Я швидко здійснив пошук і виявив наступне, але я все ще плутаю:

Відповіді:


159
  • mappedBy має бути вказано на перевернутій стороні (двонаправленої) асоціації
  • inversedBy повинен бути вказаний на власній стороні (двонаправленої) асоціації

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

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

Дивіться https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html


1
Як не дивно, документаліст доктрини вирішив залишити ямл-приклад багатостороннього двонаправленого відображення, мабуть, найбільш часто використовуваного!
Пітер Вустер

4
@PeterWooster, найкраща практика - це використання анотацій, оскільки ви маєте всю інформацію про організацію в одному місці!
Андреас Лінден

Це також стосується багатьох до багатьох відносин. Для цього: ви можете самостійно вибрати власну сторону асоціації «багато хто».
11mb

5
@AndreasLinden, що широко використовується, не означає кращої практики. Що-небудь, використовуючи коментарі для написання коду на льоту, ніколи не може вважатися найкращою практикою, це не PHP, і навіть не включається за замовчуванням у всі рамки. Маючи всю інформацію про суб'єкт господарювання в одному місці - це анти-аргумент. Оскільки при згрупуванні всього коду в одне місце - це добре? Це писати біль, це підтримувати та зменшувати організацію у вашому проекті. найкраща практика ? Дух.
JesusTheHun

4
@JesusTheHun ти порівнюєш яблука та груші. "весь код" дуже сильно відрізняється від "усієї інформації про підприємство";)
Андреас Лінден

55

Наведених вище відповідей було недостатньо для того, щоб я зрозумів, що відбувається, тому після того, як я більше заглиблююся в це, я думаю, що у мене є спосіб його пояснення, який матиме сенс для людей, які боролися, як і я.

inversedBy і mappedBy використовуються ВНУТРІШНІ ДОКТРИНИ двигуна зменшити кількість запитів SQL він повинен зробити , щоб отримати необхідну інформацію. Щоб було зрозуміло, якщо ви не додасте перевернутеBy чи 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 ), ви помітите, що в таблиці Категорія немає стовпчика на ній для завдань. (це тому, що на ньому немає анотації стовпців)

Тут важливо розуміти, що змінні завдання існують лише для того, щоб внутрішній двигун вчення міг використовувати посилання над ним, яке говорить про його категорію mappedBy. Тепер ... не плутайте тут, як я ... Категорія НЕ посилається на ІМЯ КЛАСУ , його посилання на властивість класу Завдання під назвою "захищена $ категорія".

Як і мудрий, у класі Tasks властивість $ категорії згадує, що це inversedBy = "задачі", зауважте, що це множина, це НЕ ПЛЮСЬ ІМЕНЯ КЛАСУ , а лише тому, що властивість називається "захищеними $ завданнями" у категорії клас.

Після того, як ви це зрозумієте, стає дуже легко зрозуміти, що роблять перевернутіBy та mappedBy та як їх використовувати в цій ситуації.

Сторона, яка в моєму прикладі посилається на іноземний ключ, наприклад, "завдання", завжди отримує атрибут inversedBy, оскільки він повинен знати, який клас (за допомогою команди targetEntity) та яку змінну (inversedBy =) у цьому класі, щоб "працювати назад", щоб говорити та отримувати інформацію про категорію. Простий спосіб запам’ятати це - клас, у якому був би іноземний_ід той, який повинен бути перевернутимBy.

Якщо як з категорією, так і її властивістю $ задань (якої немає на столі, пам’ятайте, лише лише частина класу для оптимізації) є «завданнями» MappedBy, це створює офіційні відносини між двома сутностями, щоб доктрина тепер могла безпечно використовувати JOIN SQL заяви замість двох окремих операторів SELECT. Без mappedBy, двигун доктрини не знав би з оператора JOIN, він створить, яку змінну в класі "Завдання" класти інформацію про категорії.

Сподіваюся, це пояснює це трохи краще.


6
Це дуже добре пояснено і дякую за ваші зусилля. Я прийшов з Ларавелом Красномовним до вчення, і мені було важко зрозуміти логіку тут. Молодці. Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category'все, що мені було потрібно. Це не тільки вирішило мою проблему, але й допомогло мені зрозуміти. Найкраща відповідь ІМО :-)
Альфа

1
Я теж родом з Красномовства, це мені дуже допомогло. Єдиний мій момент зараз - як встановити сетер / геттер для цього, я все ще навчаюся мотузки на ньому
Еман,

1
Так, це дуже просто і навіть автоматизовано з деякими інструментами там, почніть спілкуватися зі мною пізніше, і я можу вам допомогти
Джозеф Астрахан,

1
Перевірте цю відповідь, stackoverflow.com/questions/16629397/…
Йосип Астрахан,

1
symfony.com/doc/current/doctrine/associations.html , це насправді краще вчитися, symfony використовує вчення, щоб воно навчило вас тому ж.
Йосиф Астрахан

21

У двосторонніх відносинах є як власна, так і зворотна сторона

картографується : вводиться у зворотну сторону двонаправленого відношення Для посилання на свою власну сторону

перевернутий : вводиться у власну сторону двонаправленого відношення Для посилання на її зворотну сторону

І

картографуєтьсяатрибут використовується з декларацією відображення OneToOne, OneToMany або ManyToMany.

inversedBy атрибут , який використовується з OneToOne, ManyToOne або меппінга ManyToMany.

Примітка . Сторона двонаправленого відношення - сторона, що містить зовнішній ключ.

є два посилання про перевернуте By та відображене на карті в Документознавство: Перша Посилання , Друга Посилання


1
посилання мертві?
Скарамош

2

5.9.1. Володіння та зворотна сторона

Для асоціацій «Багато хто багато» ви можете вибрати, яка сутність є власником, а яка - зворотною стороною. Існує дуже просте семантичне правило, яке визначає, яка сторона з точки зору розробників є більш підходящою для того, щоб бути стороною. Вам залишається лише запитати себе, яка організація несе відповідальність за управління зв’язком, і вибрати це як сторону, що володіє.

Візьмемо приклад двох сутностей Article і тег. Щоразу, коли ви хочете підключити статтю до тегу, і навпаки, за це відношення в основному відповідає стаття. Щоразу, коли ви додаєте нову статтю, ви хочете з'єднати її з існуючими або новими тегами. Форма створення статті, ймовірно, підтримує це поняття і дозволить вказати теги безпосередньо. Ось чому ви повинні вибрати Статтю як власну сторону, оскільки це робить код більш зрозумілим:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.