Was ist der Unterschied zwischen inversedBy und mappedBy?

102

Ich entwickle meine Anwendung mit Zend Framework 2 und Doctrine 2.

Während ich Anmerkungen schreibe, kann ich den Unterschied zwischen mappedByund nicht verstehen inversedBy.

Wann soll ich verwenden mappedBy?

Wann soll ich verwenden inversedBy?

Wann sollte ich keine verwenden?

Hier ist ein Beispiel:

 /**
 *
 * @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;

Ich habe schnell gesucht und Folgendes gefunden, bin aber immer noch verwirrt:

Entwickler
quelle

Antworten:

159
  • mappedBy muss auf der inversen Seite einer (bidirektionalen) Zuordnung angegeben werden
  • inversedBy muss auf der Besitzerseite einer (bidirektionalen) Zuordnung angegeben werden

aus der Doktrinendokumentation:

  • ManyToOne ist immer die Besitzerseite einer bidirektionalen Zuordnung.
  • OneToMany ist immer die Kehrseite einer bidirektionalen Zuordnung.
  • Die Besitzerseite einer OneToOne-Zuordnung ist die Entität mit der Tabelle, die den Fremdschlüssel enthält.

Siehe https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html

Andreas Linden
quelle
1
Seltsamerweise entschied sich der Doctrine-Dokumentator, das Yaml-Beispiel einer bidirektionalen Viele-zu-Eins-Zuordnung wegzulassen, die wahrscheinlich am häufigsten verwendet wird!
Peter Wooster
4
@PeterWooster, die beste Vorgehensweise ist die Verwendung von Anmerkungen, da Sie dann alle Informationen über die Entität an einem Ort haben!
Andreas Linden
Dies gilt auch für viele zu viele Beziehungen. Für diejenigen: Sie können die Besitzerseite eines Viele-zu-Viele-Vereins selbst auswählen.
11mb
5
@AndreasLinden weit verbreitet bedeutet nicht Best Practice. Etwas, das Kommentare verwendet, um Code im laufenden Betrieb zu schreiben, kann niemals als Best Practice angesehen werden. Es ist nicht php-nativ und sogar nicht standardmäßig in allen Frameworks enthalten. Alle Informationen über eine Entität an einem Ort zu haben, ist ein Anti-Argument. Denn wenn Sie Ihren gesamten Code an einem Ort gruppieren, ist das eine gute Sache? Es ist ein Schmerz zu schreiben, ein Schmerz, die Organisation in Ihrem Projekt aufrechtzuerhalten und zu reduzieren. beste Übung ? Duh.
JesusTheHun
3
@ JesusTheHun Sie vergleichen Äpfel und Birnen. "all code" unterscheidet sich sehr stark von "all info about a entity";)
Andreas Linden
55

Die obigen Antworten reichten nicht aus, um zu verstehen, was vor sich ging. Nachdem ich mich eingehender damit befasst habe, denke ich, dass ich eine Möglichkeit habe, dies zu erklären, die für Menschen Sinn macht, die sich so schwer getan haben, es zu verstehen.

inversedBy und mappedBy werden von der INTERNAL DOCTRINE- Engine verwendet, um die Anzahl der SQL-Abfragen zu verringern, die erforderlich sind, um die benötigten Informationen abzurufen . Um klar zu sein, wenn Sie nicht inversedBy oder mappedBy hinzufügen, funktioniert Ihr Code weiterhin, wird jedoch nicht optimiert .

Schauen Sie sich zum Beispiel die folgenden Klassen an:

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;
}

Wenn Sie in diesen Klassen den Befehl zum Generieren des Schemas ausführen (z. B. bin/console doctrine:schema:update --force --dump-sql), werden Sie feststellen, dass die Kategorietabelle keine Spalte für Aufgaben enthält. (Dies liegt daran, dass es keine Spaltenanmerkung enthält.)

Das Wichtigste, was hier zu verstehen ist, ist, dass die variablen Aufgaben nur vorhanden sind, damit die interne Doktrin-Engine die Referenz darüber verwenden kann, die die Kategorie "MappedBy" angibt. Nun ... seien Sie hier nicht so verwirrt wie ich ... Kategorie bezieht sich NICHT auf den Klassennamen, sondern auf die Eigenschaft in der Task-Klasse namens 'protected $ category'.

Wie in der Tasks-Klasse erwähnt die Eigenschaft $ category, dass es sich um inversedBy = "Aufgaben" handelt. Beachten Sie, dass dies Plural ist. Dies ist NICHT DAS PLURAL DES KLASSENNAMENS , sondern nur, weil die Eigenschaft in der Kategorie 'geschützte $ Aufgaben' heißt Klasse.

Sobald Sie dies verstanden haben, wird es sehr einfach zu verstehen, was inversedBy und mappedBy tun und wie sie in dieser Situation verwendet werden.

Die Seite, die in meinem Beispiel wie 'Aufgaben' auf den Fremdschlüssel verweist, erhält immer das Attribut inversedBy, da sie wissen muss, welche Klasse (über den Befehl targetEntity) und welche Variable (inversedBy =) in dieser Klasse "rückwärts arbeiten" soll Sprechen Sie und erhalten Sie die Kategoriedaten von. Eine einfache Möglichkeit, sich daran zu erinnern, ist die Klasse, die die Foreignkey_ID haben würde, die inversedBy sein muss.

Wenn wie bei category und seiner Eigenschaft $asks (die nicht in der Tabelle enthalten ist, nur ein Teil der Klasse für Optimierungszwecke) MappedBy-Aufgaben sind, wird die Beziehung zwischen den beiden Entitäten offiziell erstellt, sodass die Doktrin jetzt sicher ist Verwenden Sie JOIN SQL-Anweisungen anstelle von zwei separaten SELECT-Anweisungen. Ohne mappedBy würde die Doctrine Engine aus der JOIN-Anweisung nicht wissen, welche Variable in der Klasse 'Task' zum Einfügen der Kategorieinformationen erstellt wird.

Hoffe das erklärt es ein bisschen besser.

Joseph Astrahan
quelle
6
Dies ist sehr gut erklärt und vielen Dank für Ihre Mühe. Ich kam von Laravel Eloquent zur Lehre und es fiel mir schwer, die Logik hier zu verstehen. Gut gemacht. Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category'alles was ich brauchte. Es hat nicht nur mein Problem gelöst, sondern mir auch geholfen, es zu verstehen. Die beste Antwort IMO :-)
The Alpha
1
Auch ich kam aus Eloquent, das hat mir sehr geholfen. Mein einziger Knackpunkt ist jetzt, wie man den Setter / Getter dafür einstellt. Ich lerne immer noch die Seile darauf
Eman
1
Ja, das ist wirklich einfach und mit einigen Tools sogar automatisiert. Starten Sie später einen Chat mit mir und ich kann Ihnen helfen
Joseph Astrahan
1
Überprüfen Sie diese Antwort heraus, stackoverflow.com/questions/16629397/…
Joseph
1
symfony.com/doc/current/doctrine/associations.html , das ist eigentlich besser zu lernen, symfony verwendet Doktrin, damit Sie das Gleiche lernen.
Joseph Astrahan
21

In bidirektionaler Beziehung hat sowohl eine besitzende Seite als auch eine umgekehrte Seite

mappedBy : in die umgekehrte Seite einer bidirektionalen Beziehung setzen, um auf ihre eigene Seite zu verweisen

inversedBy : in die Besitzerseite einer bidirektionalen Beziehung setzen Um auf ihre inverse Seite zu verweisen

UND

Attribut mappedBy , das mit der Zuordnungsdeklaration OneToOne, OneToMany oder ManyToMany verwendet wird.

InversedBy- Attribut, das mit der OneToOne-, ManyToOne- oder ManyToMany-Zuordnungsdeklaration verwendet wird.

Hinweis : Die besitzende Seite einer bidirektionalen Beziehung die Seite, die den Fremdschlüssel enthält.

Es gibt zwei Verweise auf inversedBy und mappedBy in Doctrine Documentation: First Link , Second Link

ahmed hamdy
quelle
1
Die Links sind tot?
Scaramouche
2

5.9.1. Besitz und umgekehrte Seite

Für viele-zu-viele-Assoziationen können Sie auswählen, welche Entität die Eigentümerin und welche die umgekehrte Seite ist. Es gibt eine sehr einfache semantische Regel, um zu entscheiden, welche Seite aus Entwicklersicht besser geeignet ist, die besitzende Seite zu sein. Sie müssen sich nur fragen, welche Entität für das Verbindungsmanagement verantwortlich ist, und diese als Eigentümer auswählen.

Nehmen Sie ein Beispiel für zwei Entitäten, Artikel und Tag. Wann immer Sie einen Artikel mit einem Tag verbinden möchten und umgekehrt, ist meistens der Artikel für diese Beziehung verantwortlich. Wenn Sie einen neuen Artikel hinzufügen, möchten Sie ihn mit vorhandenen oder neuen Tags verbinden. Ihr Formular zum Erstellen von Artikeln wird diesen Begriff wahrscheinlich unterstützen und es ermöglichen, die Tags direkt anzugeben. Aus diesem Grund sollten Sie den Artikel als Eigentümer auswählen, da dies den Code verständlicher macht:

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

Micheal Mouner Mikhail Youssif
quelle