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 PERSONS
e 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 pk
sul ID_DOCUMENTS
solo. 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_DOCUMENTS
verso PERSONS
e 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_DOCUMENTS
sarà 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.