Was ist die "Besitzerseite" in einem ORM-Mapping?

128

Was genau bedeutet die besitzende Seite ? Was ist eine Erklärung mit einigen Mapping-Beispielen ( eins zu viele, eins zu eins, viele zu eins )?

Der folgende Text ist ein Auszug aus der Beschreibung von @OneToOne in der Java EE 6-Dokumentation. Sie können die Seite sehen, die das Konzept besitzt .

Definiert eine einwertige Zuordnung zu einer anderen Entität mit einer Eins-zu-Eins-Multiplizität. Es ist normalerweise nicht erforderlich, die zugeordnete Zielentität explizit anzugeben, da sie normalerweise aus dem Typ des Objekts abgeleitet werden kann, auf das verwiesen wird. Wenn die Beziehung bidirektional ist, muss die nicht besitzende Seite das Element mappedBy der OneToOne-Annotation verwenden, um das Beziehungsfeld oder die Eigenschaft der besitzenden Seite anzugeben.

Nur ein Lernender
quelle
5
Ich war verloren, bis ich dies las: javacodegeeks.com/2013/04/…
darga33
2
Die DB-Tabelle mit der Fremdschlüsselspalte wird als Besitzerseite behandelt. Die Geschäftseinheit, die diese DB-Tabelle darstellt, ist also der Eigentümer (Besitzerseite) dieser Beziehung. Nicht unbedingt, aber in den meisten Fällen verfügt die Besitzerseite über eine @ JoinColumn-Annotation.
Diablo

Antworten:

202

Warum ist die Vorstellung einer Besitzerseite notwendig:

Die Idee einer Besitzerseite einer bidirektionalen Beziehung beruht auf der Tatsache, dass es in relationalen Datenbanken keine bidirektionalen Beziehungen wie bei Objekten gibt. In Datenbanken haben wir nur unidirektionale Beziehungen - Fremdschlüssel.

Was ist der Grund für den Namen "Besitzerseite"?

Die Besitzerseite der von Hibernate verfolgten Beziehung ist die Seite der Beziehung, die den Fremdschlüssel in der Datenbank besitzt.

Was ist das Problem, das der Begriff des Besitzes einer Seite löst?

Nehmen Sie ein Beispiel für zwei zugeordnete Entitäten, ohne eine Besitzerseite zu deklarieren:

@Entity
@Table(name="PERSONS")
public class Person {
    @OneToMany
    private List<IdDocument>  idDocuments;
}

@Entity
@Table(name="ID_DOCUMENTS")
public class IdDocument {
    @ManyToOne
    private Person person;
}

Aus OO-Sicht definiert diese Abbildung nicht eine bidirektionale Beziehung, sondern zwei separate unidirektionale Beziehungen.

Die Zuordnung schaffen würde nicht nur Tabellen PERSONSund ID_DOCUMENTS, sondern auch eine dritte Zuordnungstabelle erstellen PERSONS_ID_DOCUMENTS:

CREATE TABLE PERSONS_ID_DOCUMENTS
(
  persons_id bigint NOT NULL,
  id_documents_id bigint NOT NULL,
  CONSTRAINT fk_persons FOREIGN KEY (persons_id) REFERENCES persons (id),
  CONSTRAINT fk_docs FOREIGN KEY (id_documents_id) REFERENCES id_documents (id),
  CONSTRAINT pk UNIQUE (id_documents_id)
)

Beachten Sie die Primärschlüssel pkauf ID_DOCUMENTSnur. In diesem Fall verfolgt der Ruhezustand beide Seiten der Beziehung unabhängig voneinander: Wenn Sie der Beziehung ein Dokument hinzufügen Person.idDocuments, wird ein Datensatz in die Zuordnungstabelle eingefügt PERSON_ID_DOCUMENTS.

Wenn wir dagegen aufrufen idDocument.setPerson(person), ändern wir den Fremdschlüssel person_id in der Tabelle ID_DOCUMENTS. Hibernate erstellt zwei unidirektionale (Fremdschlüssel-) Beziehungen in der Datenbank, um eine bidirektionale Objektbeziehung zu implementieren .

Wie der Gedanke, eine Seite zu besitzen, das Problem löst:

Viele Male , was wir wollen , ist nur ein Fremdschlüssel auf dem Tisch ID_DOCUMENTShin PERSONSund die zusätzliche Zuordnungstabelle.

Um dies zu lösen, müssen wir den Ruhezustand so konfigurieren, dass die Änderungen an der Beziehung nicht mehr verfolgt werden Person.idDocuments. Der Ruhezustand sollte nur die andere Seite der Beziehung verfolgen. DazuIdDocument.person fügen wir mappedBy hinzu :

@OneToMany(mappedBy="person")
private List<IdDocument>  idDocuments;

Was bedeutet mappedBy?

Dies bedeutet ungefähr : "Änderungen auf dieser Seite der Beziehung werden bereits von der anderen Seite der Beziehung IdDocument.person zugeordnet, sodass Sie sie hier nicht separat in einer zusätzlichen Tabelle verfolgen müssen."

Gibt es irgendwelche GOTCHAs, Konsequenzen?

Mit mappedBy , wenn wir nur anrufenperson.getDocuments().add(document) , die Fremdschlüssel in ID_DOCUMENTSwird nicht in dem neuen Dokument verknüpft werden, denn dies ist nicht der besitz / nachverfolgt Seite der Beziehung ist!

Um das Dokument mit der neuen Person zu verknüpfen, müssen Sie explizit anrufen document.setPerson(person) , da dies die besitzende Seite der Beziehung ist.

Bei Verwendung von mappedBy liegt es in der Verantwortung des Entwicklers, die Eigentümerseite zu kennen und die richtige Seite der Beziehung zu aktualisieren, um die Persistenz der neuen Beziehung in der Datenbank auszulösen.

Angular University
quelle
17
Die beste Antwort, die ich finde, erklärt die Lehre 'mappedBy' + 'inversedBy'.
Kurt Zhong
1
Vielen Dank, dass Sie die Zuordnungen und den Grund für das Konzept angegeben haben.
Mohnish
1
Ich weiß nicht, ob sich die Dinge geändert haben, aber im Ruhezustand 5.0.9. Wenn ich "nur anrufe" person.getDocuments().add(document), aktualisiert der Ruhezustand den Fremdschlüssel ID_DOCUMENTS.
K.Nicholas
1
@ Karl Nicholas, hi, stimme dir zu, wir haben ein Kaskadenattribut für @OneToManyAnnotationen, das auf PERSIST gesetzt werden kann. In diesem Fall speichert der Ruhezustand alle verknüpften Entitäten in der Datenbank. Kann jemand dies bitte klarstellen - warum sagt der Autor, dass der Ruhezustand keine Änderungen auf der Seite des Nichtbesitzers verfolgt -, aber tatsächlich führt der Ruhezustand eine Nachverfolgung durch?
Oleksandr Papchenko
3
cascade weist den Anbieter an, die untergeordneten Entitäten zu speichern, auch wenn die übergeordnete Entität sie nicht besitzt, sodass die Regel effektiv geändert wird. Wenn Sie mappedBy = child.field hatten (oder haben) und KEINE Kaskade hatten, werden die untergeordneten Elemente der Liste nicht gespeichert. Wenn Sie kein MappingBy UND keine Kaskade hatten, besitzt das Elternteil die Beziehung. Wenn Sie NEUE Kinder in die Liste aufnehmen und dann das Elternteil speichern, wird eine Ausnahme ausgelöst, da die neuen Kinder-IDs nicht verfügbar sind in der Join-Tabelle gespeichert werden. Hoffe das klärt die Dinge ... :)
K.Nicholas
142

Sie können sich vorstellen, dass die besitzende Seite die Entität ist, die den Verweis auf die andere hat. In Ihrem Auszug haben Sie eine Eins-zu-Eins-Beziehung. Da ist es ein symmetrische Beziehung handelt, haben Sie am Ende das Gegenteil, wenn Objekt A in Beziehung zu Objekt B steht.

Dies bedeutet, dass das Speichern eines Verweises auf Objekt B in Objekt A und das Speichern eines Verweises auf Objekt A in Objekt B redundant ist. Deshalb wählen Sie, welches Objekt das andere Objekt "besitzt", das den Verweis darauf hat.

Wenn Sie eine Eins-zu-Viele-Beziehung haben, sind die Objekte, die sich auf den Teil "Viele" beziehen, die besitzende Seite, andernfalls müssten Sie viele Referenzen von einem einzelnen Objekt zu einer Vielzahl speichern. Um dies zu vermeiden, hat jedes Objekt in der zweiten Klasse einen Zeiger auf das einzelne Objekt, auf das es verweist (also sind sie die besitzende Seite).

Für eine Viele-zu-Viele-Beziehung gibt es keine eigene Seite, da Sie ohnehin eine separate Zuordnungstabelle benötigen.

Zusammenfassend ist die besitzende Seite die Entität, die den Bezug zur anderen hat.

Jack
quelle
6
Vielen Dank für Ihre Klarstellung.
Nur ein Lernender
2
Es könnte hilfreich sein, auch meine Antwort aus Gründen für die Namen 'mappedBy' und 'besitzende Seite' zu sehen. Was passiert, wenn wir keine besitzende Seite definieren, GOTCHAs, hoffe es hilft
Angular University
5
Nun, die Antwort ist größtenteils richtig, denke ich. Aber zumindest für den Ruhezustand haben sogar viele-zu-viele-Beziehungen eine eigene Seite. Dies hat beispielsweise Auswirkungen auf das Aktualisierungsverhalten. Schauen Sie sich Abschnitt 4 ("Update Hibernate Model Class") dieses Tutorials genau an
Pfiver
11
Diese Antwort verwirrt mehr als sie hilft. Was nützt es zu sagen, dass "Sie sich vorstellen können, dass die besitzende Seite die Entität ist, die den Verweis auf die andere hat", wenn in bidirektionalen Beziehungen beide Entitätsobjekte einen Verweis aufeinander haben? Außerdem ist "Für eine Viele-zu-Viele-Beziehung, da Sie ohnehin eine separate Zuordnungstabelle benötigen, keine Besitzerseite" einfach falsch: @ManyToManyBeziehungen haben auch Besitzerseiten. In ähnlicher Weise können @OneToManyBeziehungen Verknüpfungstabellen verwenden, und Sie müssen immer noch eine Besitzerseite angeben.
DavidS
5
Grundsätzlich ist dies eine nette Wohlfühlantwort, die positive Stimmen hat, weil sie leichter zu verstehen ist als die Wahrheit.
DavidS