¿Por qué es necesaria la noción de un lado propietario?
La idea del lado propietario de una relación bidireccional proviene del hecho de que en las bases de datos relacionales no hay relaciones bidireccionales como en el caso de los objetos. En las bases de datos solo tenemos relaciones unidireccionales: claves foráneas.
¿Cuál es la razón del nombre 'lado propietario'?
El lado propietario de la relación rastreada por Hibernate es el lado de la relación que posee la clave externa en la base de datos.
¿Cuál es el problema que resuelve la noción de ser propietario?
Tome un ejemplo de dos entidades mapeadas sin declarar un lado propietario:
@Entity
@Table(name="PERSONS")
public class Person {
@OneToMany
private List<IdDocument> idDocuments;
}
@Entity
@Table(name="ID_DOCUMENTS")
public class IdDocument {
@ManyToOne
private Person person;
}
Desde el punto de vista de OO, este mapeo define no una relación bidireccional, sino dos relaciones unidireccionales separadas.
La asignación crearía no solo tablas PERSONS
y ID_DOCUMENTS
, sino que también crearía una tercera tabla de asociación 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)
)
Note la clave principal pk
en ID_DOCUMENTS
solamente. En este caso, Hibernate rastrea ambos lados de la relación de forma independiente: si agrega un documento a una relación Person.idDocuments
, inserta un registro en la tabla de asociación PERSON_ID_DOCUMENTS
.
Por otro lado, si llamamos idDocument.setPerson(person)
, cambiamos la clave externa person_id en la tabla ID_DOCUMENTS
. Hibernate está creando dos relaciones unidireccionales (clave externa) en la base de datos, para implementar una relación de objeto bidireccional.
Cómo la noción de ser propietario resuelve el problema:
Muchas veces lo que queremos es solo una clave externa en la tabla ID_DOCUMENTS
hacia PERSONS
y la tabla de asociación adicional.
Para resolver esto, necesitamos configurar Hibernate para que deje de rastrear las modificaciones en relación Person.idDocuments
. Hibernate solo debe rastrear el otro lado de la relación IdDocument.person
, y para ello agregamos mappedBy :
@OneToMany(mappedBy="person")
private List<IdDocument> idDocuments;
¿Qué significa mappedBy?
Esto significa algo como: "las modificaciones en este lado de la relación ya están asignadas por
el otro lado de la relación IdDocument.person, por lo que no es necesario rastrearlo aquí por separado en una tabla adicional".
¿Hay alguna GOTCHA, consecuencias?
Usando mappedBy , Si sólo nos llamamos person.getDocuments().add(document)
, la clave externa de ID_DOCUMENTS
lo NO estar relacionado con el nuevo documento, ya que este no es el / lado propietario seguimiento de la relación!
Para vincular el documento a la nueva persona, debe llamar explícitamente document.setPerson(person)
, porque ese es el lado propietario de la relación.
Al usar mappedBy , es responsabilidad del desarrollador saber cuál es el lado propietario y actualizar el lado correcto de la relación para activar la persistencia de la nueva relación en la base de datos.