638 Stimmen

JPA JoinColumn vs. mappedBy

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

y

@Entity
public class Company {

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

644voto

Óscar López Punkte 224631

Der Vermerk @JoinColumn zeigt an, dass es sich bei dieser Einheit um die Eigentümer der Beziehung (d.h.: die entsprechende Tabelle hat eine Spalte mit einem Fremdschlüssel zur referenzierten Tabelle), während das Attribut mappedBy bedeutet, dass die Entität auf dieser Seite die Umkehrung der Beziehung ist und der Eigentümer in der "anderen" Entität liegt. Das bedeutet auch, dass Sie von der Klasse, die Sie mit "mappedBy" annotiert haben, auf die andere Tabelle zugreifen können (vollständig bidirektionale Beziehung).

Insbesondere für den Code in der Frage würden die korrekten Anmerkungen wie folgt aussehen:

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

@Entity
public class Branch {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "companyId")
    private Company company;
}

269voto

Mike Punkte 18362

@JoinColumn kann auf beiden Seiten der Beziehung verwendet werden. Die Frage bezog sich auf die Verwendung von @JoinColumn über die @OneToMany Seite (seltener Fall). Und der Punkt ist hier in Vervielfältigung physischer Informationen (Spaltenname) zusammen mit nicht optimierte SQL-Abfrage, die einige zusätzliche UPDATE Aussagen .

Nach Angaben von Dokumentation :

Desde viele zu eins sind (fast) immer die Eigentümerseite einer bidirektionalen Beziehung in der JPA-Spezifikation wird die Eins-zu-Viele-Assoziation mit dem Wort @OneToMany(mappedBy=...)

@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 mit Soldier durch das Gelände der Truppe. Sie müssen (dürfen) kein physisches Mapping in der mappedBy Seite.

Um ein bidirektionales one to many abzubilden, wird mit der Eins-zu-Viel-Seite als besitzende Seite müssen Sie die mappedBy Element und setzen Sie das many auf eins @JoinColumn como insertable y updatable auf falsch. Diese Lösung ist nicht optimiert und erzeugt einige zusätzliche UPDATE Erklärungen.

@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() {
    ...
}

154voto

Vlad Mihalcea Punkte 121171

Unidirektionale Eins-zu-Viel-Zuordnung

Wenn Sie die @OneToMany Vermerk mit @JoinColumn dann haben Sie eine unidirektionale Assoziation, wie die zwischen dem Elternteil Post Entität und das Kind PostComment in der folgenden Abbildung:

Unidirectional one-to-many association

Bei einer unidirektionalen one-to-many Assoziation wird die Assoziation nur von der übergeordneten Seite zugeordnet.

In diesem Beispiel wird nur die Post Entität definiert eine @OneToMany Verbindung zum Kind PostComment Einheit:

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "post_id")
private List<PostComment> comments = new ArrayList<>();

Bidirektionale Eins-zu-Viel-Verknüpfung

Wenn Sie die @OneToMany mit dem mappedBy Attribut gesetzt ist, haben Sie eine bidirektionale Assoziation. In unserem Fall sind sowohl die Post Entität hat eine Sammlung von PostComment Kind-Entitäten, und das Kind PostComment Entität hat einen Verweis zurück auf die übergeordnete Post wie das folgende Diagramm zeigt:

Bidirectional one-to-many association

In der PostComment Einheit, die post wird die Entitätseigenschaft wie folgt abgebildet:

@ManyToOne(fetch = FetchType.LAZY)
private Post post;

Der Grund, warum wir explizit die fetch Attribut zu FetchType.LAZY ist, weil standardmäßig alle @ManyToOne y @OneToOne Assoziationen werden eifrig abgerufen, was zu N+1-Abfrageproblemen führen kann.

In der Post Einheit, die comments Assoziation wird wie folgt abgebildet:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

En mappedBy Attribut des @OneToMany Anmerkung verweist auf die post Eigenschaft im Kind PostComment Entität, und auf diese Weise weiß Hibernate, dass die bidirektionale Assoziation von der @ManyToOne Seite, die für die Verwaltung des Wertes der Fremdschlüsselspalte zuständig ist, auf dem diese Tabellenbeziehung basiert.

Für eine bidirektionale Assoziation benötigen Sie außerdem zwei Hilfsmethoden, wie addChild y removeChild :

public void addComment(PostComment comment) {
    comments.add(comment);
    comment.setPost(this);
}

public void removeComment(PostComment comment) {
    comments.remove(comment);
    comment.setPost(null);
}

Diese beiden Methoden stellen sicher, dass beide Seiten der bidirektionalen Assoziation synchronisiert sind. Ohne die Synchronisierung beider Seiten garantiert Hibernate nicht, dass Änderungen des Assoziationsstatus an die Datenbank weitergegeben werden.

Welches soll man wählen?

Die unidirektionale @OneToMany Die Assoziation ist nicht sehr leistungsfähig, daher sollten Sie sie vermeiden.

Besser ist es, die bidirektionale @OneToMany was effizienter ist.

48voto

IqbalHamid Punkte 1926

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

Es ist NICHT @JoinColumn was bedeutet, dass diese Entität der Eigentümer der Beziehung ist. Stattdessen ist es die @ManyToOne Anmerkung, die dies tut (in seinem Beispiel).

Die Beziehungsanmerkungen wie @ManyToOne , @OneToMany y @ManyToMany JPA/Hibernate auffordern ein Mapping erstellen. Standardmäßig wird dies über eine separate Join-Tabelle durchgeführt.

@JoinColumn

Der Zweck der @JoinColumn ist die Schaffung eines Join-Spalte i nicht bereits existiert. Wenn dies der Fall ist, dann ist dies Name die Join-Spalte.

MappedBy

Der Zweck der MappedBy Parameter soll JPA anweisen: NICHT eine weitere Join-Tabelle erstellen, da die Beziehung bereits durch durch die gegenüber Einheit dieser Beziehung.

Erinnern Sie sich: MappedBy ist eine Eigenschaft der Beziehungsannotationen, deren Zweck es ist, einen Mechanismus zu erzeugen, um zwei Entitäten in Beziehung zu setzen, was standardmäßig durch die Erstellung einer Join-Tabelle geschieht. MappedBy stoppt diesen Prozess in einer Richtung.

Die Entität, die nicht MappedBy gilt als die Eigentümer der Beziehung, da die Mechanik der Zuordnung innerhalb ihrer Klasse durch die Verwendung einer der drei Zuordnungsannotationen zum Fremdschlüsselfeld vorgegeben wird. Damit wird nicht nur die Art des Mappings festgelegt, sondern auch die Erstellung einer Join-Tabelle angewiesen. Darüber hinaus besteht die Möglichkeit, die Join-Tabelle zu unterdrücken, indem die @JoinColumn-Annotation auf den Fremdschlüssel angewendet wird, wodurch dieser stattdessen in der Tabelle der Eigentümerentität verbleibt.

Zusammengefasst: @JoinColumn erstellt entweder eine neue Joinspalte oder benennt eine bestehende um; während die MappedBy Parameter arbeitet mit den Beziehungsannotationen der anderen (untergeordneten) Klasse zusammen, um eine Zuordnung entweder durch eine Join-Tabelle oder durch die Erstellung einer Fremdschlüsselspalte in der zugehörigen Tabelle der Eigentümerentität zu erstellen.

Um zu veranschaulichen, wie MapppedBy funktioniert, sehen Sie sich den folgenden Code an. Wenn MappedBy gelöscht werden, würde Hibernate tatsächlich ZWEI Join-Tabellen erstellen! Warum? Weil es bei Many-to-Many-Beziehungen eine Symmetrie gibt und Hibernate keinen Grund hat, eine Richtung gegenüber der anderen zu wählen.

Wir verwenden daher MappedBy um Hibernate zu informieren, haben wir gewählt den anderen Entität, um die Abbildung der Beziehung zwischen den beiden Entitäten festzulegen.

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

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

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

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

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

38voto

Soumyaansh Punkte 8048

Der Vermerk mappedBy sollte idealerweise immer auf der Elternseite (Klasse "Unternehmen") der bidirektionalen Beziehung verwendet werden, in diesem Fall in der Klasse "Unternehmen", die auf die Member-Variable "Unternehmen" der Klasse "Kind" (Klasse "Branche") zeigt.

Der Vermerk @JoinColumn wird verwendet, um eine zugeordnete Spalte für den Beitritt zu einer Entitätsassoziation anzugeben. Diese Anmerkung kann in jeder Klasse (Eltern- oder Kindklasse) verwendet werden, aber sie sollte idealerweise nur in einer Seite verwendet werden (entweder in der Elternklasse oder in der Kindklasse, nicht in beiden).

Im Folgenden finden Sie ein Arbeitsbeispiel:

übergeordnete Klasse , Unternehmen

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

}

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

}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X