web-dev-qa-db-de.com

Was ist der Unterschied zwischen unidirektionalen und bidirektionalen JPA- und Hibernate-Assoziationen?

Was ist der Unterschied zwischen unidirektionalen und bidirektionalen Assoziationen?

Da die in der Datenbank generierten Tabellen alle gleich sind, bestand 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?

120
hguser

Der Hauptunterschied besteht darin, dass die bidirektionale Beziehung den Navigationszugriff in beide Richtungen ermöglicht, 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 ein Group vor, das Tausende von Users enthält:

  • Wie würden Sie darauf zugreifen? Bei so vielen Users müssen Sie normalerweise eine Filterung und/oder Paginierung anwenden, damit Sie trotzdem eine Abfrage ausführen müssen (es sei denn, Sie verwenden Sammlungsfilterung , was wie ein Hack aussieht für mich). Einige Entwickler tendieren in solchen Fällen möglicherweise dazu, Filter im Speicher anzuwenden, was offensichtlich nicht gut für die Leistung ist. Beachten Sie, dass eine solche Beziehung diese Art von Entwicklern ermutigen kann, sie zu verwenden, ohne die Auswirkungen auf die Leistung zu berücksichtigen.

  • Wie würden Sie dem User neue Group hinzufügen? Glücklicherweise betrachtet Hibernate die Eigentümerseite der Beziehung, wenn Sie diese beibehalten, sodass Sie nur User.group Festlegen können. Wenn Sie jedoch Objekte im Speicher konsistent halten möchten, müssen Sie auch User zu Group.users Hinzufügen. Aber es würde Hibernate veranlassen, alle Elemente von Group.users Aus der Datenbank abzurufen!

Daher kann ich der Empfehlung von Best Practices nicht zustimmen. Sie müssen bidirektionale Beziehungen sorgfältig entwerfen und dabei die Anwendungsfälle (benötigen Sie Navigationszugriff in beide Richtungen?) Und mögliche Auswirkungen auf die Leistung berücksichtigen.

Siehe auch:

132
axtavt

Es gibt zwei Hauptunterschiede.

Zugang zu den Vereinsseiten

Der erste bezieht sich darauf, wie Sie auf die Beziehung zugreifen. Bei einer unidirektionalen Zuordnung können Sie in der Zuordnung nur von einem Ende aus navigieren.

Also, für eine unidirektionale @ManyToOne Assoziation bedeutet, dass Sie nur von der untergeordneten Seite auf die Beziehung zugreifen können, auf der sich der Fremdschlüssel befindet.

Wenn Sie ein unidirektionales @OneToMany Assoziation bedeutet, 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 Assoziation können Sie die Assoziation auf beide Arten navigieren, entweder von der übergeordneten oder von der untergeordneten Seite.

Sie müssen auch verwenden Sie die Dienstprogrammmethoden add/remove für bidirektionale Zuordnungen, um sicherzustellen, dass beide Seiten ordnungsgemäß synchronisiert sind .

Performance

Der zweite Aspekt betrifft die Leistung.

  1. Zum @OneToMany, nidirektionale Assoziationen funktionieren nicht so gut wie bidirektionale .
  2. Zum @OneToOne, Bei einer bidirektionalen Zuordnung wird das übergeordnete Element eifrig abgerufen, wenn der Ruhezustand nicht erkennen kann, ob der Proxy zugewiesen werden soll, oder ein Nullwert .
  3. Zum @ManyToMany, Der Auflistungstyp macht einen großen Unterschied, da Sets eine bessere Leistung erzielt als Lists .
18
Vlad Mihalcea

Bezüglich der Codierung ist die Implementierung einer bidirektionalen Beziehung komplexer, da die Anwendung gemäß JPA-Spezifikation 5 (auf Seite 42) dafür verantwortlich ist, dass beide Seiten synchron bleiben. Leider enthält das in der Spezifikation angegebene Beispiel keine näheren Angaben, sodass es keine Vorstellung vom Komplexitätsgrad gibt.

Wenn Sie keinen Cache der zweiten Ebene verwenden, ist es normalerweise kein Problem, die Beziehungsmethoden nicht korrekt zu implementieren, da die Instanzen am Ende der Transaktion verworfen werden.

Wenn bei Verwendung des Cache der zweiten Ebene aufgrund falsch implementierter Beziehungsbehandlungsmethoden etwas beschädigt wird, bedeutet dies, dass auch andere Transaktionen die beschädigten Elemente sehen (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 keinen Sinn ergibt.

Ich bin nicht zu 100% sicher, dass dies der einzige Unterschied ist, aber es ist der Hauptunterschied Unterschied. Es wird auch empfohlen, dass die Hibernate-Dokumente bidirektionale Zuordnungen haben:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html

Speziell:

Bidirektionale Assoziationen bevorzugen: Unidirektionale Assoziationen sind schwieriger abzufragen. In einer großen Anwendung müssen fast alle Zuordnungen in Abfragen in beide Richtungen navigierbar sein.

Ich persönlich habe ein kleines Problem mit dieser Pauschalempfehlung - es scheint mir, dass es Fälle gibt, in denen ein Kind keinen praktischen Grund hat, über seine Eltern Bescheid zu wissen (z. B. warum ein Bestellartikel müssen über die Reihenfolge Bescheid wissen, mit der es verbunden ist?), aber ich sehe Wert darin auch einen angemessenen Teil der Zeit. Und da die Bidirektionalität nicht wirklich schadet, finde ich es nicht zu verwerflich, daran festzuhalten.

9
kvista