Qual è il "lato proprietario" in una mappatura ORM?


129

Cosa significa esattamente la parte proprietaria ? Qual è una spiegazione con alcuni esempi di mappatura ( uno a molti, uno a uno, molti a uno )?

Il seguente testo è un estratto della descrizione di @OneToOne nella documentazione Java EE 6. Puoi vedere il concetto che possiede il lato in esso.

Definisce un'associazione a valore singolo con un'altra entità che ha una molteplicità uno a uno. Normalmente non è necessario specificare esplicitamente l'entità target associata poiché di solito può essere dedotta dal tipo di oggetto a cui si fa riferimento. Se la relazione è bidirezionale, il lato non proprietario deve utilizzare l'elemento mappedBy dell'annotazione OneToOne per specificare il campo relazione o la proprietà del lato proprietario.



5
Ero perso fino a quando ho letto questo: javacodegeeks.com/2013/04/…
darga33

2
La tabella DB con la colonna chiave esterna viene considerata come lato proprietario. Quindi l'entità aziendale che rappresenta quella tabella DB è il proprietario (lato proprietario) di quella relazione. Non necessariamente, ma la maggior parte dei casi Owning-side avrà l'annotazione @JoinColumn.
Diablo,

Risposte:


202

Perché è necessaria la nozione di una parte proprietaria:

L'idea di un lato proprietario di una relazione bidirezionale deriva dal fatto che nei database relazionali non vi sono relazioni bidirezionali come nel caso degli oggetti. Nei database abbiamo solo relazioni unidirezionali: chiavi esterne.

Qual è la ragione del nome "lato proprietario"?

Il lato proprietario della relazione tracciata da Hibernate è il lato della relazione che possiede la chiave esterna nel database.

Qual è il problema risolto dall'idea di possedere un lato?

Prendi un esempio di due entità mappate senza dichiarare un lato proprietario:

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

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

Da un punto di vista OO questa mappatura definisce non una relazione bidirezionale, ma due relazioni unidirezionali separate.

Il mapping creerebbe non solo tabelle PERSONSe ID_DOCUMENTS, ma creerebbe anche una terza tabella di associazione 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)
)

Si noti la chiave primaria pksul ID_DOCUMENTSsolo. In questo caso Hibernate tiene traccia di entrambi i lati della relazione in modo indipendente: se aggiungi un documento alla relazione Person.idDocuments, inserisce un record nella tabella delle associazioni PERSON_ID_DOCUMENTS.

D'altra parte, se chiamiamo idDocument.setPerson(person), cambiamo la chiave esterna person_id sulla tabella ID_DOCUMENTS. Hibernate sta creando due relazioni unidirezionali (chiave esterna) sul database, per implementare una relazione oggetto bidirezionale.

In che modo l'idea di possedere una parte risolve il problema:

Molte volte ciò che vogliamo è solo una chiave esterna nella tabella ID_DOCUMENTSverso PERSONSe nella tabella delle associazioni extra.

Per risolvere questo problema, dobbiamo configurare Hibernate in modo da interrompere il tracciamento delle modifiche in relazione Person.idDocuments. Hibernate dovrebbe tracciare solo l' altro lato della relazione IdDocument.person, e per farlo aggiungiamo mappedBy :

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

Che cosa significa mappedBy?

Questo significa qualcosa come: "le modifiche da questa parte della relazione sono già mappato l'altro lato della IdDocument.person relazione, quindi nessun bisogno di tenere traccia qui separatamente in un tavolo extra."

Ci sono dei GOTCHA, delle conseguenze?

Utilizzando mappedBy , Se chiamiamo solo person.getDocuments().add(document), la chiave esterna in ID_DOCUMENTSsarà NON essere collegato al nuovo documento, perché questo non è il possessore / lato monitorati del rapporto!

Per collegare il documento alla nuova persona, è necessario chiamare esplicitamente document.setPerson(person), poiché quello è il lato proprietario della relazione.

Quando utilizza mappedBy , è responsabilità dello sviluppatore sapere qual è il lato proprietario e aggiornare il lato corretto della relazione al fine di innescare la persistenza della nuova relazione nel database.


17
La migliore risposta che trovo spiega la dottrina 'mappedBy' + 'inversedBy'.
Kurt Zhong,

1
Grazie per aver specificato i mapping e il motivo alla base del concetto.
Mohnish,

1
Non so se le cose sono cambiate, ma su Hibernate 5.0.9. Finale se "chiamo solo person.getDocuments().add(document)", ibernazione aggiorna la chiave esterna ID_DOCUMENTS.
K. Nicholas,

1
@Karl Nicholas, ciao, d'accordo con te, abbiamo un attributo a cascata @OneToManysull'annotazione che può essere impostato su PERSIST in questo caso l'ibernazione salverà tutte le entità collegate nel DB. Qualcuno può chiarire questo, perché l'autore afferma che l'ibernazione non terrà traccia delle modifiche da parte non proprietaria, ma in realtà l'ibernazione esegue il monitoraggio?
Oleksandr Papchenko,

3
cascata indica al provider di salvare le entità figlio anche se l'entità padre non le possiede, quindi modifica in modo efficace la regola. Se avessi (o avessi) mappedBy = child.field e NON avessi a cascata, i figli dell'elenco non verrebbero salvati. Inoltre, se non hai mappatoBy E non hai fatto il collegamento in cascata, il genitore possiede la relazione e se metti NUOVI figli nell'elenco e poi salvi il genitore genererà un'eccezione perché i nuovi ID figli non sono disponibili per essere salvato nella tabella di join. Spero che chiarisca le cose ... :)
K. Nicholas il

142

Puoi immaginare che il lato proprietario sia l'entità che ha il riferimento all'altro. Nel tuo estratto, hai una relazione uno a uno. Dal momento che è una relazione simmetrica , finirai per avere che se l'oggetto A è in relazione con l'oggetto B, allora anche il viceversa è vero.

Ciò significa che il salvataggio nell'oggetto A di un riferimento all'oggetto B e il salvataggio nell'oggetto B di un riferimento all'oggetto A saranno ridondanti: ecco perché si sceglie quale oggetto "possiede" l'altro con il riferimento ad esso.

Quando hai una relazione uno-a-molti, gli oggetti relativi alla parte "molti" saranno il lato proprietario, altrimenti dovresti memorizzare molti riferimenti da un singolo oggetto a una moltitudine. Per evitarlo, ogni oggetto nella seconda classe avrà un puntatore al singolo a cui si riferiscono (quindi sono il lato proprietario).

Per una relazione molti-a-molti, poiché avrai comunque bisogno di una tabella di mappatura separata, non ci sarà alcun lato proprietario.

In conclusione, il lato proprietario è l'entità che ha il riferimento all'altro.


6
Grazie per il tuo chiarimento.
Solo uno studente

2
potrebbe essere utile vedere qui sotto anche la mia risposta per le ragioni dei nomi "mappedBy" e "lato proprietario", cosa succede se non definiamo un lato proprietario, GOTCHA, spero che aiuti
Università angolare

5
Bene, la risposta è per lo più corretta credo. Ma almeno per Hibernate, anche le relazioni molti-a-molti hanno un lato proprietario. Ciò ha implicazioni per il comportamento di aggiornamento, ad esempio. Dai
Pfiver

11
Questa risposta confonde più di quanto aiuti. A che serve dire che "Puoi immaginare che il lato proprietario sia l'entità che ha il riferimento all'altro" quando nelle relazioni bidirezionali, entrambi gli oggetti Entità avranno un riferimento reciproco? Inoltre, "Per una relazione molti-a-molti, poiché avrai comunque bisogno di una tabella di mappatura separata non ci sarà alcun lato proprietario" è semplicemente errato: anche le @ManyToManyrelazioni hanno lati proprietari. Allo stesso modo, le @OneToManyrelazioni possono usare le tabelle di join e devi ancora specificare un lato proprietario.
DavidS

5
Fondamentalmente, questa è una risposta carina e piacevole che ha voti positivi perché è più facile da capire della verità.
DavidS,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.