Kursinhalt
Java-Datenmanipulation mit Hibernate
Java-Datenmanipulation mit Hibernate
Entitätsbeziehungen und Kaskadentypen
Entitätsbeziehungen
Wie Sie vielleicht aus dem Kurs über relationale Datenbanken und Normalisierung wissen, gibt es in SQL bestimmte Beziehungen zwischen Tabellen. Ähnlich verhält es sich in Hibernate, wo eine Entität eine andere referenzieren kann und umgekehrt. Diese werden als Entitätsbeziehungen bezeichnet. Es gibt insgesamt 4 Arten solcher Beziehungen.
Eins-zu-Eins
Dieser Beziehungstyp zeigt an, dass eine Entität nur mit einer anderen Entität verbunden ist. Zum Beispiel kann ein Land nur eine Hauptstadt haben. Wenn wir dies in Bezug auf Tabellen und Entitäten darstellen, wird es eine Eins-zu-Eins-Beziehung zwischen ihnen geben. In Hibernate verwenden wir zur Spezifizierung einer solchen Beziehung die @OneToOne
Annotation:
Wenn diese Annotation über einem Entitätsfeld vorhanden ist, wird in der entsprechenden Tabelle eine Fremdschlüsselspalte erstellt, die einen Verweis auf den Bezeichner der zugehörigen Entität enthält.
Es wird so aussehen:
Offensichtlich werden in der "cities"-Tabelle Hauptstädte mit ihren IDs gespeichert. Zum Beispiel wird unter der ID 4 "Managua" stehen, unter 11 "Washington" und so weiter.
One-to-Many
In einer solchen Beziehung wird eine Entität mit mehreren anderen Entitäten verbunden sein. Es ist leicht zu verstehen mit dem Beispiel eines Regisseurs und seiner Filme. Ein Regisseur kann viele verschiedene Filme haben, aber jeder Film sollte nur einen Regisseur haben.
Hinweis
Ja, ich weiß, dass es Fälle gibt, in denen mehrere Regisseure an einem Film arbeiten, aber für unser Beispiel ist das jetzt nicht wichtig.
Um eine solche Beziehung zu kennzeichnen, wird die @OneToMany
-Annotation über dem Feld in der Entitätsklasse platziert. Das Feld muss eine Liste sein:
Wenn eine solche Annotation über dem Feld vorhanden ist, wird eine separate Tabelle in der Datenbank erstellt, die die Kennungen dieser Entität und der zugehörigen Entität enthält.
Es wird so aussehen:
Solche IDs werden auf beide Entitäten verweisen und die Beziehungen zwischen ihnen anzeigen.
Viele-zu-Eins
Bei diesem Typ sind viele Entitäten mit einer verbunden. Man könnte es als das Gegenteil von Eins-zu-Viele betrachten, und das wäre korrekt. Für ein besseres Verständnis, betrachten Sie das Beispiel der Studenten-Universitäts-Beziehungen. Viele Studenten können mit einer Universität verbunden sein.
Um eine solche Beziehung herzustellen, müssen Sie die @ManyToOne
Annotation über dem Feld angeben, das keine Sammlung ist:
Wenn diese Annotation über dem Entitätsfeld vorhanden ist, erhält die entsprechende Tabelle eine Fremdschlüsselspalte, die einen Verweis auf den Bezeichner der zugehörigen Entität enthält.
Es wird so aussehen:
Dies ähnelt One-to-One, aber hier können verschiedene Studenten denselben Verweis auf die Universitäts-ID haben.
Viele-zu-Viele
In dieser Art von Beziehung sind viele Entitäten mit vielen Entitäten verbunden. Sie können sich diese Beziehung in Bezug auf einen Fahrer und ein Auto vorstellen. Ein Fahrer kann viele Autos haben, und ein Auto kann viele Fahrer haben (zum Beispiel in einem Taxiservice).
Im Code müssen Sie die @ManyToMany
Annotation über dem Feld in der Entität platzieren:
Wenn diese Annotation über einem Feld der Entität vorhanden ist (das eine Sammlung sein muss), wird in der Datenbank eine separate Tabelle erstellt, die Identifikatoren der aktuellen Entität und der zugehörigen Entität enthält.
Es wird so aussehen:
Wie Sie sehen können, kann ein Fahrer mehrere Autos haben, und ebenso kann ein Auto mehrere Fahrer haben.
Sie haben vielleicht bemerkt, dass wir in einigen Fällen die Annotation nur in einer Klasse angeben müssen, während es in anderen Fällen notwendig ist, sie gleichzeitig in beiden Entitätsklassen anzugeben. Lassen Sie uns dies genauer besprechen.
Unidirektionale und Bidirektionale Beziehungen
Unidirektionale und bidirektionale Beziehungen zwischen Entitäten zeigen an, wie sie interagieren.
-
Unidirektionale Beziehungen: Dies sind die Beziehungen, die wir zuvor besprochen haben. In einer solchen Beziehung wird die Beziehungsannotation nur in einer Entitätsklasse angegeben. Einfach ausgedrückt, die Klasse, die das annotierte Feld enthält, weiß, dass sie mit einer anderen Klasse in Beziehung steht, während die andere Klasse, die die Annotation nicht enthält, sich der Beziehung nicht bewusst ist. Es ist nicht kompliziert, aber wir sind mehr an dem zweiten Fall interessiert;
-
Bidirektionale Beziehungen: In dieser Art von Beziehung ist Klasse
A
sich ihrer Beziehung zu KlasseB
bewusst, ebenso wie KlasseB
sich ihrer Beziehung zu KlasseA
bewusst ist. Die Beziehungsannotation wird in beiden Entitätsklassen angegeben und sieht folgendermaßen aus:
A
B
@Entity public class A { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; @OneToMany private List<B> list; }
Interaktion zwischen diesen beiden Entitäten erfolgt in beide Richtungen.
Um Konsistenz während der Datenoperationen sicherzustellen, müssen wir die "besitzende Seite" und die "inverse Seite" definieren. Die besitzende Seite ist die Seite, die die Beziehung kontrolliert, und Aktualisierungen der Beziehung in der Datenbank erfolgen nur nach Änderungen auf der besitzenden Seite.
Um die besitzende Seite zu bestimmen, verwenden wir einen Parameter in der Beziehungsannotation. Der mappedBy
-Parameter verwendet den Namen des Feldes in der Entität, die wir zur besitzenden Seite machen wollen. Mit anderen Worten, wir verwenden diese Annotation in der Entität, die wir zur inversen Seite machen wollen.
Für ein klareres Beispiel, lassen Sie uns die Klasse B
zur besitzenden Seite machen:
Jetzt ist die Entität B
die besitzende Seite in diesen bidirektionalen Beziehungen geworden. Die Daten werden nur dann in die Datenbank geschrieben, wenn Änderungen in der Klasse B
vorgenommen werden.
Dies wird verwendet, um die Erstellung einer neuen Tabelle zu vermeiden, die die Bezeichner dieser beiden Entitäten enthält. Stattdessen wird nun eine separate Spalte, "A_id
", zur Tabelle der Entität B
hinzugefügt, in der die Beziehungs-IDs angegeben werden.
Es gilt als gute Praxis, die "ManyToOne"-Seite zur besitzenden Seite zu machen. Bei bidirektionalen Beziehungen "Many-to-Many" kann jede Seite als besitzende Seite festgelegt werden.
Später werden wir dies in der Praxis anwenden, und Sie werden besser verstehen, wie es funktioniert und warum es notwendig ist.
Abrufarten
In Entitätsbeziehungen werden verschiedene Abrufarten verwendet. Es gibt zwei davon, lassen Sie uns jede besprechen:
-
EAGER bedeutet, dass alle notwendigen Daten in einer einzigen Abfrage abgerufen werden. Wenn wir eine Entität aus der Datenbank abrufen, die
@OneToOne
oder@ManyToOne
Felder hat, erhalten wir auch vollständige Informationen über diese verwandten Entitäten. Das bedeutet, dass wir mit einer Abfrage an die Datenbank sofort Informationen aus zwei Tabellen abrufen, was Ressourcen, Speicher und Ausführungszeit verbraucht. Eine solche Abrufart hat erhebliche Auswirkungen auf die Optimierung; -
LAZY bedeutet, dass Daten aus der Datenbank nur dann abgerufen werden, wenn sie tatsächlich für eine bestimmte Operation benötigt werden. Wenn wir eine Entität aus der Datenbank abrufen, die
@OneToMany
oder@ManyToMany
Felder hat, erhalten wir keine Informationen über diese verwandten Entitäten. Dies ist ein wesentlicher Vorteil, da wir keine unnötigen Informationen aus der Datenbank abrufen, nur die Daten, die wir benötigen. Das bedeutet, dass nur die Tabelle, auf die wir uns beziehen, betroffen ist, ohne die Tabellen zu berühren, die mit dieser Entität verbunden sind.
Hinweis
Es ist ziemlich einfach, sich das zu merken: Beziehungen, die auf
Many
enden, haben eine Abrufart von LAZY; der Rest wird EAGER sein.
Es wird empfohlen, immer die LAZY-Abrufart zu verwenden, da sie den Code optimierter macht. Sie können dies mit dem Befehl fetch = FetchType.LAZY
in den Annotationsparametern tun.
So sieht es im Code aus:
Nun, wenn wir eine Abfrage für diese Entität ausführen, werden wir nur sie beeinflussen und nur auf andere Daten zugreifen, wenn es notwendig ist.
Kaskadentypen
Jetzt, da wir gelernt haben, wie wir nur mit der Entität interagieren, mit der wir arbeiten, lernen wir, wie wir spezifische Felder angeben, auf die die Interaktion bei der Beziehung von Entitäten in jedem Fall propagiert werden soll. Kaskaden werden uns dabei helfen.
Hinweis
Solche Kaskaden sind Teil der JPA ( Jakarta Persistence API ) Bibliothek, die die Elternklasse von Hibernate ist. Daher können wir in Hibernate auch solche Klassen verwenden.
Es gibt insgesamt 4 Typen:
PERSIST
— das Aufrufen derpersist()
-Methode wird auf verwandte Entitäten übertragen;MERGE
— das Aufrufen dermerge()
-Methode wird auf verwandte Entitäten übertragen;REMOVE
— das Aufrufen derremove()
-Methode wird auf verwandte Entitäten übertragen;ALL
- alle oben genannten Operationen werden auf verwandte Entitäten übertragen.
Jeder dieser Kaskadentypen erfüllt seinen Zweck.
Stellen wir uns eine Situation vor, in der wir einen neuen Studenten speichern und Änderungen auch an der "Universitäten"-Tabelle vorgenommen werden sollen, zum Beispiel Erhöhung der Anzahl der Studenten.
So können wir dies umsetzen:
In diesem Fall werden bei Änderungen mit der persist()
-Methode an der Student-Entität auch Änderungen an der University-Entität vorgenommen.
Zuweisung einer Abteilung zu einem Mitarbeiter
Für den Moment ist die beängstigende Theorie in diesem Kapitel abgeschlossen.
Erinnern wir uns nun an das Mitarbeiterverwaltungsprojekt, an dem wir gearbeitet haben, und denken wir über die Beziehung zwischen den Employee
- und Department
-Entitäten nach.
Es ist offensichtlich, dass ein Mitarbeiter nur in einer Abteilung arbeiten kann, während viele Mitarbeiter in einer Abteilung arbeiten können. In diesem Fall können wir schließen, dass eine One-to-Many-Beziehung von der Seite des Employee
und eine Many-to-One-Beziehung von der Seite des Department
hergestellt wird.
Lassen Sie uns eine unidirektionale Beziehung in diesen Tabellen herstellen.
Um dies zu erreichen, fügen wir die Annotation @ManyToOne(fetch = FetchType.LAZY)
hinzu und verwenden auch die neue Annotation JoinColumn(name = "department_id")
, um die Erstellung einer neuen Tabelle zu vermeiden.
Ja, dieser Ansatz hat auch seinen Platz, da bidirektionale Beziehungen ziemlich komplex zu verstehen und zu implementieren sind, und auf diese Weise erhalten wir die Vorteile von bidirektionalen Beziehungen ohne unnötigen Aufwand.
Die Employee
-Entität wird so aussehen:
Es sind keine weiteren Änderungen erforderlich, da Hibernate alles für uns erledigt. Nun verwenden wir die getAll()
-Methode, die im vorherigen Kapitel implementiert wurde, um die Änderungen zu sehen:
1. Welche Art von Beziehung wird am besten durch einen Regisseur und seine Filme dargestellt?
2. In einer Viele-zu-Eins-Beziehung, wo wird die Fremdschlüsselspalte erstellt?
3. Was bedeutet die @ManyToMany
Annotation in Hibernate?
4. Welcher Fetch-Typ wird empfohlen, um Code in Hibernate zu optimieren?
5. Welche Annotation wird verwendet, um bei der Definition einer Many-to-One-Beziehung in Hibernate den Spaltennamen in der Datenbank anzugeben?
Danke für Ihr Feedback!