Was ist der Unterschied zwischen unidirektionalen und bidirektionalen Assoziationen?
Da die in der Datenbank generierte Tabelle alle gleich ist, besteht der einzige Unterschied darin, dass sich jede Seite der bidirektionalen Zuordnungen auf die andere bezieht und die unidirektionale nicht.
Dies ist eine unidirektionale Zuordnung
public class User {
private int id;
private String name;
@ManyToOne
@JoinColumn(
name = "groupId")
private Group group;
}
public class Group {
private int id;
private String name;
}
Die bidirektionale Assoziation
public class User {
private int id;
private String name;
@ManyToOne
@JoinColumn(
name = "groupId")
private Group group;
}
public class Group {
private int id;
private String name;
@OneToMany(mappedBy="group")
private List<User> users;
}
Der Unterschied besteht darin, ob die Gruppe eine Referenz des Benutzers enthält.
Ich frage mich also, ob dies der einzige Unterschied ist. was wird empfohlen?
Antworten:
Der Hauptunterschied besteht darin, dass die bidirektionale Beziehung einen Navigationszugriff in beide Richtungen bietet, sodass Sie ohne explizite Abfragen auf die andere Seite zugreifen können. Außerdem können Sie Kaskadenoptionen auf beide Richtungen anwenden.
Beachten Sie, dass der Navigationszugriff nicht immer gut ist, insbesondere für "Eins-zu-Sehr-Viele" - und "Viele-zu-Sehr-Viele" -Beziehungen. Stellen Sie sich eine vor
Group
, die Tausende vonUser
s enthält :Wie würden Sie darauf zugreifen? Bei so vielen
User
s müssen Sie normalerweise eine Filterung und / oder Paginierung anwenden, damit Sie trotzdem eine Abfrage ausführen müssen (es sei denn, Sie verwenden eine Sammlungsfilterung , die für mich wie ein Hack aussieht). Einige Entwickler neigen in solchen Fällen dazu, Filterung im Speicher anzuwenden, was offensichtlich nicht gut für die Leistung ist. Beachten Sie, dass eine solche Beziehung diese Art von Entwicklern dazu ermutigen kann, sie zu verwenden, ohne die Auswirkungen auf die Leistung zu berücksichtigen.Wie würden Sie dem neue
User
s hinzufügenGroup
? Glücklicherweise betrachtet Hibernate die eigene Seite der Beziehung, wenn sie beibehalten wird, sodass Sie nur festlegen könnenUser.group
. Wenn Sie jedoch wollen Objekte im Speicher konsistent zu halten, müssen Sie auch hinzufügenUser
zuGroup.users
. Aber es würde Hibernate dazu bringen, alle ElementeGroup.users
aus der Datenbank abzurufen !Daher kann ich der Empfehlung der Best Practices nicht zustimmen . Sie müssen bidirektionale Beziehungen sorgfältig entwerfen und dabei Anwendungsfälle (benötigen Sie einen Navigationszugriff in beide Richtungen?) Und mögliche Auswirkungen auf die Leistung berücksichtigen.
Siehe auch:
quelle
setGroup()
aus ,addUser()
um beiden Seiten in Einklang zu halten.setGroup()
ohne aufrufenaddUser()
, dies würde jedoch zu einem inkonsistenten Status der Objekte im Speicher führen.Es gibt zwei Hauptunterschiede.
Zugriff auf die Assoziationsseiten
Der erste bezieht sich darauf, wie Sie auf die Beziehung zugreifen. Bei einer unidirektionalen Zuordnung können Sie die Zuordnung nur von einem Ende aus navigieren.
Für eine unidirektionale
@ManyToOne
Zuordnung bedeutet dies, dass Sie nur von der untergeordneten Seite auf die Beziehung zugreifen können, auf der sich der Fremdschlüssel befindet.Wenn Sie eine unidirektionale
@OneToMany
Zuordnung haben, bedeutet dies, dass Sie nur von der übergeordneten Seite auf die Beziehung zugreifen können, auf der sich der Fremdschlüssel befindet.Für die bidirektionale
@OneToMany
Zuordnung können Sie in der Zuordnung auf beide Arten navigieren, entweder von der übergeordneten oder von der untergeordneten Seite.Sie müssen auch Dienstprogrammmethoden zum Hinzufügen / Entfernen für bidirektionale Zuordnungen verwenden, um sicherzustellen, dass beide Seiten ordnungsgemäß synchronisiert sind .
Performance
Der zweite Aspekt bezieht sich auf die Leistung.
@OneToMany
, unidirektionale Assoziationen nicht ausführen sowie bidirektionale diejenigen .@OneToOne
, führt dazu , dass eine bidirektionale Vereinigung der Eltern geholt eifrig sein , wenn Hibernate nicht , ob der Proxy sollte oder ein Nullwert zugewiesen werden kann sagen .@ManyToMany
, macht die Sammlung Art schon ein Unterschied , wieSets
eine bessere Leistung alsLists
.quelle
In Bezug auf die Codierung ist die Implementierung einer bidirektionalen Beziehung komplexer, da die Anwendung dafür verantwortlich ist, beide Seiten gemäß JPA-Spezifikation 5 (auf Seite 42) synchron zu halten. Leider enthält das in der Spezifikation angegebene Beispiel keine näheren Angaben, sodass es keine Vorstellung vom Grad der Komplexität gibt.
Wenn Sie keinen Cache der zweiten Ebene verwenden, ist es normalerweise kein Problem, die Beziehungsmethoden nicht korrekt implementiert zu haben, da die Instanzen am Ende der Transaktion verworfen werden.
Wenn bei Verwendung des Cache der zweiten Ebene etwas aufgrund falsch implementierter Methoden zur Behandlung von Beziehungen beschädigt wird, bedeutet dies, dass auch bei anderen Transaktionen die beschädigten Elemente angezeigt werden (der Cache der zweiten Ebene ist global).
Eine korrekt implementierte bidirektionale Beziehung kann Abfragen und den Code vereinfachen, sollte jedoch nicht verwendet werden, wenn dies in Bezug auf die Geschäftslogik nicht wirklich sinnvoll ist.
quelle
Ich bin nicht 100% sicher, dass dies der einzige Unterschied ist, aber es ist der Hauptunterschied . Es wird auch empfohlen, bidirektionale Assoziationen durch die Hibernate-Dokumente zu haben:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html
Speziell:
Ich persönlich habe ein kleines Problem mit dieser Decke Empfehlung - scheint es mir , gibt es Fälle , in denen ein Kind keinen praktischen Grund hat über seine Eltern kennen (zB warum eine Auftragsposition Bedarf über den Auftrag wissen , es ist verbunden mit?), aber ich sehe auch einen angemessenen Teil der Zeit darin Wert. Und da die Bidirektionalität nichts wirklich schadet, finde ich es nicht zu verwerflich, daran festzuhalten.
quelle