it-swarm.com.de

Was ist der Unterschied zwischen @JoinColumn und mappedBy, wenn eine JPA @OneToMany-Zuordnung verwendet wird?

Was ist der Unterschied zwischen:

@Entity
public class Company {

    @OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
    @JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
    private List<Branch> branches;
    ...
}

und

@Entity
public class Company {

    @OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY, mappedBy = "companyIdRef")
    private List<Branch> branches;
    ...
}
474

@JoinColumn konnte auf beiden Seiten der Beziehung verwendet werden. Die Frage betraf die Verwendung von @JoinColumn auf dem @OneToMany. Seite (seltener Fall). Und hier geht es um die Vervielfältigung physischer Informationen (Spaltenname) zusammen mit einer nicht optimierten SQL-Abfrage, die einige zusätzliche UPDATE-Anweisungen erzeugt. .

Nach Dokumentation :

Da viele zu eins sind (fast) immer die Eigentümerseite eines Die bidirektionale Beziehung in der JPA-Spezifikation, die Zuordnung von eins zu vielen, wird von @OneToMany (mappedBy = ...) mit Anmerkungen versehen.

@Entity
public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
} 

Troop hat eine bidirektionale Eins-zu-Viele-Beziehung zu Soldier über das Truppenvermögen. Sie müssen (dürfen) keine physischen Zuordnungen auf der mappedBy-Seite definieren.

Um ein bidirektionales Eins-zu-Viele-Element mit der Eins-zu-Viele-Seite als Besitzerseite zuzuordnen, müssen Sie das Element mappedBy entfernen und die Vielen festlegen auf eine @ JoinColumn als einfügbar und aktualisierbar auf falsch. Diese Lösung ist nicht optimiert und führt zu zusätzlichen UPDATE-Anweisungen.

@Entity
public class Troop {
    @OneToMany
    @JoinColumn(name="troop_fk") //we need to duplicate the physical information
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk", insertable=false, updatable=false)
    public Troop getTroop() {
    ...
}
207

Die Anmerkung @JoinColumn gibt an, dass diese Entität Eigentümer der Beziehung ist (d. H. Die entsprechende Tabelle hat eine Spalte mit einem Fremdschlüssel zur referenzierten Tabelle), wohingegen das Attribut mappedBy gibt an, dass die Entität auf dieser Seite das Gegenteil der Beziehung ist und der Eigentümer in der "anderen" Entität residiert. Dies bedeutet auch, dass Sie über die Klasse, die Sie mit "mappedBy" kommentiert haben, auf die andere Tabelle zugreifen können (vollständig bidirektionale Beziehung).

Insbesondere für den Code in der Frage würden die richtigen Anmerkungen so aussehen:

@Entity
public class Company {
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
    private List<Branch> branches;
}

@Entity
public class Branch {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "companyId")
    private Company company;
}
516
Óscar López

Wie ich in diesem Artikel erklärt habe, haben Sie eine unidirektionale Zuordnung, wenn Sie die Annotation @OneToMany mit @JoinColumn verwenden.

Wenn Sie den @OneToMany mit dem Attributsatz mappedBy verwenden, haben Sie eine bidirektionale Zuordnung. Dies bedeutet, dass Sie auf der untergeordneten Seite eine @ManyToOne Zuordnung haben müssen, auf die sich die mappedBy bezieht.

Die nidirektionale @OneToMany Zuordnung funktioniert nicht sehr gut , daher sollten Sie dies vermeiden.

Verwenden Sie besser bidirektionaler @OneToMany, was effizienter ist .

42
Vlad Mihalcea

Die Annotation mappedBy sollte idealerweise immer in der Parent-Seite (Company-Klasse) der bidirektionalen Beziehung verwendet werden, in diesem Fall in der Company-Klasse, die auf die Mitgliedsvariable 'company' der Child-Klasse verweist (Zweigklasse)

Die Annotation @ JoinColumn wird verwendet, um eine zugeordnete Spalte für den Beitritt zu einer Entitätszuordnung anzugeben. Diese Annotation kann in jeder Klasse (Parent oder Child) verwendet werden, sollte jedoch idealerweise nur auf einer Seite (entweder in) verwendet werden Elternklasse oder in der Kindklasse nicht in beiden) hier in diesem Fall habe ich es in der Kindseite (Zweigklasse) der bidirektionalen Beziehung verwendet, die den Fremdschlüssel in der Zweigklasse anzeigt.

unten ist das Arbeitsbeispiel:

Elternklasse, Firma

@Entity
public class Company {


    private int companyId;
    private String companyName;
    private List<Branch> branches;

    @Id
    @GeneratedValue
    @Column(name="COMPANY_ID")
    public int getCompanyId() {
        return companyId;
    }

    public void setCompanyId(int companyId) {
        this.companyId = companyId;
    }

    @Column(name="COMPANY_NAME")
    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    @OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="company")
    public List<Branch> getBranches() {
        return branches;
    }

    public void setBranches(List<Branch> branches) {
        this.branches = branches;
    }


}

ntergeordnete Klasse, Zweig

@Entity
public class Branch {

    private int branchId;
    private String branchName;
    private Company company;

    @Id
    @GeneratedValue
    @Column(name="BRANCH_ID")
    public int getBranchId() {
        return branchId;
    }

    public void setBranchId(int branchId) {
        this.branchId = branchId;
    }

    @Column(name="BRANCH_NAME")
    public String getBranchName() {
        return branchName;
    }

    public void setBranchName(String branchName) {
        this.branchName = branchName;
    }

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="COMPANY_ID")
    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }


}
32
Coral

Ich möchte nur hinzufügen, dass @JoinColumn nicht immer mit dem Ort der physischen Information in Beziehung stehen muss, wie dies die Antwort nahelegt. Sie können @JoinColumn mit @OneToMany kombinieren, auch wenn die übergeordnete Tabelle keine Tabellendaten enthält, die auf die untergeordnete Tabelle verweisen.

Definieren einer unidirektionalen OneToMany-Beziehung in JPA

nidirektional OneToMany, No Inverse ManyToOne, No Join Table

Es scheint jedoch nur in JPA 2.x+ verfügbar zu sein. Dies ist in Situationen nützlich, in denen die untergeordnete Klasse nur die ID des übergeordneten Elements enthalten soll und keine vollständige Referenz.

19
Snekse

Ich bin mit der hier akzeptierten Antwort von Óscar López nicht einverstanden. Diese Antwort ist falsch!

Es ist NOT @JoinColumn, das angibt, dass diese Entität der Eigentümer der Beziehung ist. Stattdessen ist es die Annotation @ManyToOne, die dies tut (in seinem Beispiel).

Die Beziehungsannotationen wie @ManyToOne, @OneToMany und @ManyToMany weisen JPA/Hibernate an, eine Zuordnung zu erstellen. Standardmäßig erfolgt dies über eine separate Verknüpfungstabelle.


@ JoinColumn

Der Zweck von @JoinColumn ist das Erstellen einer Join-Spalte , falls noch keine vorhanden ist. Wenn dies der Fall ist, kann diese Annotation verwendet werden, um die Verknüpfungsspalte zu benennen .


MappedBy

Der Zweck des Parameters MappedBy besteht darin, JPA anzuweisen: Erstellen Sie KEINE weitere Verknüpfungstabelle, da die Beziehung bereits von der gegenüberliegenden Entität zugeordnet wird dieser Beziehung.



Denken Sie daran: MappedBy ist eine Eigenschaft der Beziehungsannotationen, deren Zweck es ist, einen Mechanismus zum Verknüpfen von zwei Entitäten zu generieren, die standardmäßig durch Erstellen einer Verknüpfungstabelle erstellt werden. MappedBy stoppt diesen Vorgang in eine Richtung.

Die Entität, die MappedBy nicht verwendet, wird als Eigentümer der Beziehung bezeichnet, da die Mechanik der Zuordnung innerhalb ihrer Klasse durch die Verwendung vorgegeben wird einer der drei Zuordnungsanmerkungen für das Fremdschlüsselfeld. Dadurch wird nicht nur die Art der Zuordnung festgelegt, sondern auch die Erstellung einer Verknüpfungstabelle angewiesen. Darüber hinaus besteht die Möglichkeit, die Verknüpfungstabelle zu unterdrücken, indem Sie die Annotation @JoinColumn auf den Fremdschlüssel anwenden, der stattdessen in der Tabelle der Eigentümerentität verbleibt.

Zusammenfassend: @JoinColumn erstellt entweder eine neue Verknüpfungsspalte oder benennt eine vorhandene um. Der Parameter MappedBy arbeitet mit den Beziehungsannotationen der anderen (untergeordneten) Klasse zusammen, um eine Zuordnung entweder über eine Verknüpfungstabelle oder durch Erstellen einer Fremdschlüsselspalte in der zugeordneten Tabelle der Eigentümerentität zu erstellen.

Betrachten Sie den folgenden Code, um zu veranschaulichen, wie MapppedBy funktioniert. Wenn der Parameter MappedBy gelöscht würde, würde Hibernate tatsächlich ZWEI Verknüpfungstabellen erstellen! Warum? Weil es eine Symmetrie in vielen Beziehungen gibt und Hibernate keine Gründe hat, eine Richtung über die andere zu wählen.

Wir verwenden daher MappedBy, um Hibernate mitzuteilen. Wir haben die andere Entität ausgewählt, um die Zuordnung der Beziehung zu diktieren zwischen den beiden Einheiten.

@Entity
public class Driver {
    @ManyToMany(mappedBy = "drivers")
    private List<Cars> cars;
}

@Entity
public class Cars {
    @ManyToMany
    private List<Drivers> drivers;
}

Das Hinzufügen von @JoinColumn (name = "driverID") in der Eigentümerklasse (siehe unten) verhindert die Erstellung einer Verknüpfungstabelle und erstellt stattdessen eine Fremdschlüsselspalte driverID in der Cars-Tabelle, um eine Zuordnung zu erstellen:

@Entity
public class Driver {
    @ManyToMany(mappedBy = "drivers")
    private List<Cars> cars;
}

@Entity
public class Cars {
    @ManyToMany
    @JoinColumn(name = "driverID")
    private List<Drivers> drivers;
}
11
IqbalHamid

JPA ist eine Ebenen-API, die verschiedenen Ebenen haben ihre eigenen Anmerkungen. Die höchste Ebene ist die (1) Entitätsebene, die persistente Klassen beschreibt. Dann haben Sie die (2) relationale Datenbankebene, die davon ausgeht, dass die Entitäten einer relationalen Datenbank zugeordnet sind, und (3) das Modell Java.

Anmerkungen der Ebene 1: @Entity, @Id, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany. Sie können Persistenz in Ihre Anwendung einbringen, indem Sie nur diese allgemeinen Anmerkungen verwenden. Aber dann müssen Sie Ihre Datenbank gemäß den von JPA getroffenen Annahmen erstellen. Diese Anmerkungen geben das Entitäts-/Beziehungsmodell an.

Anmerkungen der Ebene 2: @Table, @Column, @JoinColumn, ... Beeinflussen Sie die Zuordnung von Entitäten/Eigenschaften zu den relationalen Datenbanktabellen/-spalten, wenn Sie mit den Standardwerten von JPA nicht zufrieden sind oder einer vorhandenen Datenbank zugeordnet werden müssen. Diese Anmerkungen können als Implementierungsanmerkungen angesehen werden und geben an, wie das Mapping durchgeführt werden soll.

Meiner Meinung nach ist es am besten, sich so weit wie möglich an die Anmerkungen auf hoher Ebene zu halten und die Anmerkungen auf niedrigerer Ebene nach Bedarf einzuführen.

Zur Beantwortung der Fragen: Das @ OneToMany/mappedBy ist am nettesten, da es nur die Anmerkungen aus der Entitätsdomäne verwendet. Die @ oneToMany/@ JoinColumn ist ebenfalls in Ordnung, verwendet jedoch eine Implementierungsanmerkung, wenn dies nicht unbedingt erforderlich ist.

0