Jaka jest „strona właścicielska” w mapowaniu ORM?


128

Co dokładnie oznacza strona będąca właścicielem ? Jakie jest wyjaśnienie z kilkoma przykładami mapowania ( jeden do wielu, jeden do jednego, wiele do jednego )?

Poniższy tekst jest fragmentem opisu @OneToOne w dokumentacji Java EE 6. Widać w tym koncepcję będącą właścicielem .

Definiuje jednowartościowe powiązanie z inną jednostką, która ma wielokrotność jeden do jednego. Zwykle nie jest konieczne jawne określanie skojarzonej jednostki docelowej, ponieważ zwykle można to wywnioskować z typu obiektu, do którego się odwołujemy. Jeśli relacja jest dwukierunkowa, strona niebędąca właścicielem musi użyć elementu mappedBy adnotacji OneToOne, aby określić pole relacji lub właściwość strony będącej właścicielem.



5
Byłem zagubiony, dopóki tego nie przeczytałem: javacodegeeks.com/2013/04/ ...
darga33

2
Tabela bazy danych z kolumną klucza obcego jest traktowana jako strona będąca właścicielem. Zatem jednostka biznesowa reprezentująca tę tabelę DB jest właścicielem (stroną właściciela) tej relacji. Niekoniecznie, ale większość przypadków po stronie właściciela będzie miała adnotację @JoinColumn.
Diablo

Odpowiedzi:


202

Dlaczego pojęcie strony będącej właścicielem jest konieczne:

Idea strony właścicielskiej relacji dwukierunkowej bierze się stąd, że w relacyjnych bazach danych nie ma relacji dwukierunkowych, jak w przypadku obiektów. W bazach danych mamy tylko relacje jednokierunkowe - klucze obce.

Jaki jest powód nazwy „strona właścicielska”?

Strona będąca właścicielem relacji śledzonej przez Hibernate to strona relacji, która jest właścicielem klucza obcego w bazie danych.

Jaki problem rozwiązuje pojęcie posiadania strony?

Weźmy przykład dwóch obiektów zmapowanych bez deklarowania strony będącej właścicielem:

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

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

Z punktu widzenia obiektu obiektowego to odwzorowanie definiuje nie jedną relację dwukierunkową, ale dwie oddzielne relacje jednokierunkowe.

Mapowanie spowodowałoby nie tylko tabele PERSONSi ID_DOCUMENTS, ale także utworzyć trzecią tabelę skojarzeń 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)
)

Zwróć uwagę tylko pkna klucz podstawowy ID_DOCUMENTS. W tym przypadku Hibernate śledzi obie strony relacji niezależnie: jeśli dodasz dokument do relacji Person.idDocuments, wstawi on rekord do tabeli asocjacji PERSON_ID_DOCUMENTS.

Z drugiej strony, jeśli wywołasz idDocument.setPerson(person), zmieniamy klucz obcy person_id w tabeli ID_DOCUMENTS. Hibernate tworzy w bazie danych dwie relacje jednokierunkowe (klucz obcy) w celu zaimplementowania jednej dwukierunkowej relacji z obiektem.

Jak pojęcie strony właścicielskiej rozwiązuje problem:

Wiele razy to, czego chcemy, to tylko klucz obcy w tabeli w ID_DOCUMENTSkierunku PERSONSi dodatkowa tabela asocjacji.

Aby rozwiązać ten problem, musimy tak skonfigurować Hibernację, aby przestała śledzić modyfikacje relacji Person.idDocuments. Hibernacja powinna śledzić tylko drugą stronę relacji IdDocument.personi w tym celu dodajemy mappedBy :

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

Co to znaczy mappedBy?

Oznacza to coś takiego: „modyfikacje po tej stronie relacji są już odwzorowane przez drugą stronę relacji IdDocument.person, więc nie ma potrzeby śledzenia ich tutaj oddzielnie w dodatkowej tabeli”.

Czy są jakieś GOTCHA, konsekwencje?

Korzystanie mappedBy , jeżeli tylko zadzwonić person.getDocuments().add(document), klucz obcy w ID_DOCUMENTSbędzie nie być związane z nowym dokumentem, ponieważ to nie jest będącym właścicielem / śledzone strona relacji!

Aby połączyć dokument z nową osobą, musisz jawnie wywołać document.setPerson(person), ponieważ jest to strona będąca właścicielem relacji.

Podczas korzystania z mappedBy deweloper jest odpowiedzialny za poznanie strony będącej właścicielem i zaktualizowanie właściwej strony relacji w celu wyzwolenia trwałości nowej relacji w bazie danych.


17
Najlepsza odpowiedź, jaką znalazłem, wyjaśnia doktrynę „mapped by” + „inversedBy”.
Kurt Zhong

1
Dziękujemy za określenie mapowań i przyczyny tej koncepcji.
Mohnish

1
Nie wiem, czy coś się zmieniło, ale w Hibernate 5.0.9. Ostatecznie, jeśli „tylko dzwonię person.getDocuments().add(document)”, hibernacja aktualizuje klucz obcy ID_DOCUMENTS.
K.Nicholas,

1
@Karl Nicholas, cześć, zgadzam się z tobą, mamy atrybut kaskadowy w @OneToManyadnotacji, który można ustawić na UTRZYMAJ, w tym przypadku hibernacja zapisze wszystkie połączone jednostki w bazie danych. Czy ktoś może to wyjaśnić - dlaczego autor mówi, że hibernacja nie będzie śledzić zmian po stronie nie będącej właścicielem - ale w rzeczywistości hibernacja wykonuje śledzenie?
Oleksandr Papchenko

3
kaskada mówi dostawcy, aby zapisał jednostki podrzędne, nawet jeśli jednostka nadrzędna ich nie posiada, więc skutecznie modyfikuje regułę. Gdybyś miał (lub miał) mappedBy = child.field i NIE miałeś kaskady, wtedy elementy podrzędne listy nie zostałyby zapisane. Ponadto, jeśli nie masz mappedBy I nie masz kaskady, to Rodzic jest właścicielem relacji i jeśli umieścisz NOWE dzieci na liście, a następnie zapiszesz Rodzica, zgłosi wyjątek, ponieważ nowe identyfikatory dzieci nie są dostępne dla zostać zapisane w tabeli dołączania. Mam nadzieję, że to wszystko wyjaśnia ... :)
K.Nicholas

142

Możesz sobie wyobrazić, że stroną będącą właścicielem jest byt, który ma odniesienie do drugiej. W swoim fragmencie masz relację jeden do jednego. Ponieważ jest to relacja symetryczna , w końcu uzyskasz to, że jeśli obiekt A jest w relacji z obiektem B, to również odwrotnie jest prawdą.

Oznacza to, że zapisanie w obiekcie A odniesienia do obiektu B i zapisanie w obiekcie B odniesienia do obiektu A będzie zbędne: dlatego wybierasz, który obiekt „jest właścicielem” drugiego, który ma do niego odniesienie.

Gdy masz relację jeden do wielu, obiekty związane z częścią „wiele” będą stroną będącą właścicielem, w przeciwnym razie będziesz musiał przechowywać wiele odniesień od pojedynczego obiektu do wielu. Aby tego uniknąć, każdy obiekt w drugiej klasie będzie miał wskaźnik do pojedynczego obiektu, do którego się odnosi (więc jest stroną będącą właścicielem).

W przypadku relacji wiele do wielu, ponieważ i tak będziesz potrzebować osobnej tabeli mapowania, nie będzie żadnej strony będącej właścicielem.

Podsumowując, strona będąca właścicielem jest podmiotem, który ma odniesienie do drugiej.


6
Dziękuję Ci za wyjaśnienie.
Tylko uczeń

2
Pomocne może być również zobaczenie poniżej mojej odpowiedzi z powodów nazw `` mappedBy '' i `` owning side '', co się stanie, jeśli nie zdefiniujemy strony będącej właścicielem, GOTCHAs, mam nadzieję, że to pomoże
Angular University

5
Cóż, odpowiedź jest w większości poprawna. Ale przynajmniej w przypadku Hibernate nawet relacje „wiele do wielu” mają swoją stronę. Ma to wpływ na przykład na zachowanie aktualizacji. Przyjrzyj się bliżej sekcji 4 („Aktualizacja klasy modelu hibernacji”) tego samouczka: viralpatel.net/blogs/ ...
Pfiver

11
Ta odpowiedź bardziej dezorientuje niż pomaga. Cóż z tego powiedzieć, że „Możesz sobie wyobrazić, że stroną będącą właścicielem jest jednostka, która ma odniesienie do drugiej”, kiedy w relacjach dwukierunkowych oba obiekty Entity będą miały do ​​siebie odniesienie? Ponadto stwierdzenie „W przypadku relacji wiele do wielu, ponieważ i tak będziesz potrzebować oddzielnej tabeli mapowania, nie będzie strony będącej właścicielem” jest po prostu niepoprawne: @ManyToManyrelacje również mają strony będące właścicielami. Podobnie, @OneToManyrelacje mogą używać tabel łączenia, ale nadal musisz określić stronę będącą właścicielem.
DavidS,

5
Zasadniczo jest to urocza, dobra odpowiedź, która ma pozytywne opinie, ponieważ jest łatwiejsza do zrozumienia niż prawda.
DavidS,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.