¿Cuál es el "lado propietario" en un mapeo ORM?

129

¿Qué significa exactamente el lado propietario ? ¿Qué es una explicación con algunos ejemplos de mapeo ( uno a muchos, uno a uno, muchos a uno )?

El siguiente texto es un extracto de la descripción de @OneToOne en la documentación de Java EE 6. Puedes ver el lado propietario del concepto .

Define una asociación de un solo valor a otra entidad que tiene multiplicidad uno a uno. Normalmente no es necesario especificar explícitamente la entidad objetivo asociada, ya que generalmente se puede inferir del tipo de objeto al que se hace referencia. Si la relación es bidireccional, el lado no propietario debe usar el elemento mappedBy de la anotación OneToOne para especificar el campo de relación o la propiedad del lado propietario.

Solo un alumno
fuente
55
Estaba perdido hasta que leí esto: javacodegeeks.com/2013/04/…
darga33
2
La tabla DB con la columna de clave externa se trata como el lado propietario. Por lo tanto, la entidad comercial que representa esa tabla de base de datos es el Propietario (lado propietario) de esa relación. No necesariamente, pero la mayoría de los casos del lado propietario tendrá la anotación @JoinColumn.
Diablo

Respuestas:

202

¿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 PERSONSy 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 pken ID_DOCUMENTSsolamente. 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_DOCUMENTShacia PERSONSy 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_DOCUMENTSlo 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.

Universidad angular
fuente
17
La mejor respuesta que encuentro explica la Doctrina 'mappedBy' + 'inversedBy'.
Kurt Zhong
1
Gracias por especificar las asignaciones y la razón detrás del concepto.
Mohnish
1
No sé si las cosas han cambiado, pero en Hibernate 5.0.9. Finalmente si "solo llamo person.getDocuments().add(document)", hibernate actualiza la clave foránea ID_DOCUMENTS.
K.Nicholas
1
@Karl Nicholas, hola, de acuerdo con usted, tenemos un atributo en cascada en la @OneToManyanotación que se puede establecer en PERSIST en este caso, hibernate guardará todas las entidades vinculadas en la base de datos. ¿Alguien puede aclarar esto? ¿Por qué el autor dice que hibernate no rastreará los cambios en el lado no propietario? Sino que de hecho hibernado realiza el seguimiento?
Oleksandr Papchenko el
3
Cascade le dice al proveedor que guarde las entidades secundarias incluso si la entidad principal no las posee, por lo que modifica la regla de manera efectiva. Si tuviera (o tuviera) mappedBy = child.field y NO tuviera una cascada, entonces los elementos secundarios de la lista no se guardarían. Además, si no tenía mappedBy AND no tenía cascada, entonces el padre es dueño de la relación y si coloca NUEVOS niños en la lista y luego guarda al padre, arrojará una excepción porque los nuevos ID de niños no están disponibles para ser guardado en la tabla de unión. Espero que eso aclare las cosas ... :)
K.Nicholas
142

Puedes imaginar que el lado propietario es la entidad que tiene la referencia al otro. En tu extracto, tienes una relación uno a uno. Ya que es simétrico relación , terminarás teniendo que si el objeto A está en relación con el objeto B, entonces también lo contrario es cierto.

Esto significa que guardar en el objeto A una referencia al objeto B y guardar en el objeto B una referencia al objeto A será redundante: es por eso que elige qué objeto "posee" el otro que tiene la referencia a él.

Cuando tiene una relación de uno a muchos, los objetos relacionados con la parte "muchos" serán el lado propietario, de lo contrario, tendría que almacenar muchas referencias de un solo objeto a una multitud. Para evitar eso, cada objeto en la segunda clase tendrá un puntero al único al que se refieren (por lo que son el lado propietario).

Para una relación de muchos a muchos, ya que necesitará una tabla de mapeo separada de todos modos, no habrá ningún lado propietario.

En conclusión, el lado propietario es la entidad que tiene la referencia al otro.

Jack
fuente
66
Gracias por tu aclaración.
Solo aprendiz
2
También podría ayudar ver abajo mi respuesta por razones de los nombres 'mappedBy' y 'owning side', qué sucede si no definimos un lado propietario, GOTCHA, espero que ayude
Angular University
55
Bueno, la respuesta es mayormente correcta, supongo. Pero al menos para Hibernate, incluso las relaciones de muchos a muchos tienen un lado propietario. Esto tiene implicaciones para el comportamiento de actualización, por ejemplo. Eche un vistazo de cerca a la sección 4 ("Actualizar clase de modelo de Hibernate") de este tutorial: viralpatel.net/blogs/…
Pfiver
11
Esta respuesta confunde más de lo que ayuda. ¿De qué sirve decir que "se pueden imaginar que el lado propietario es la entidad que tiene la referencia al otro" cuando en las relaciones bidireccionales, ambos objetos de la Entidad tendrán una referencia el uno al otro? Además, "Para una relación de muchos a muchos, ya que de todos modos necesitará una tabla de mapeo separada, no habrá ningún lado propietario" es simplemente incorrecto: las @ManyToManyrelaciones también tienen lados propietarios. Del mismo modo, las @OneToManyrelaciones pueden usar tablas de unión, y aún debe especificar un lado propietario.
DavidS
55
Básicamente, esta es una respuesta linda y agradable que tiene votos positivos porque es más fácil de entender que la verdad.
DavidS