Modo más eficiente de mapear una relación @OneToMany con JPA e Hibernate
Elegí abrir este post con esta cita porque soy fan de Linus Torvalds.😉
Este es mi primer artículo. En este voy a cubrir todos los casos posibles en One-to-Many/Many-to-One
asociación de entidades. Los restantes Many-to-Many
y One-to-One
serán cubiertos en próximos artículos.
Espero que esto ayude definitivamente a todos los novatos que quieran aprender jpa/hibernate, Por favor, lea todo el artículo 😛
NOTA:
Aquí he cubierto todos los casos posibles de
One-to-Many/Many-to-One
mapeo. Entre todos, la asociación bidireccional `@OneToMany` es la mejor manera de mapear una relación de base de datos de uno a muchos.
La asociación hibernada se clasifica en One-to-One
, One-to-Many/Many-to-One
y Many-to-Many
.
- La dirección de una relación puede ser bidireccional o unidireccional.
- Una relación bidireccional tiene tanto un lado propietario como un lado inverso.
- Una relación unidireccional sólo tiene un lado propietario. El lado propietario de una relación determina cómo el tiempo de ejecución de Persistence realiza las actualizaciones de la relación en la base de datos.
- Unidireccional es una relación en la que uno de los lados no conoce la relación.
- En una relación unidireccional, sólo una entidad tiene un campo de relación o una propiedad que hace referencia a la otra. Por ejemplo, Partida tendría un campo de relación que identifica a Producto, pero Producto no tendría un campo de relación o propiedad para Partida. En otras palabras, Artículo de línea sabe sobre Producto, pero Producto no sabe qué instancias de Artículo de línea se refieren a él.
Relaciones bidireccionales:
- La relación bidireccional proporciona acceso de navegación en ambas direcciones, de modo que se puede acceder al otro lado sin consultas explícitas.
- En una relación bidireccional, cada entidad tiene un campo de relación o propiedad que se refiere a la otra entidad. A través del campo o propiedad de relación, el código de una clase de entidad puede acceder a su objeto relacionado. Si una entidad tiene un campo de relación, se dice que la entidad «conoce» su objeto relacionado. Por ejemplo, si Orden sabe qué instancias de Partida tiene y si Partida sabe a qué Orden pertenece, tienen una relación bidireccional.
Las relaciones bidireccionales deben seguir estas reglas.
- El lado inverso de una relación bidireccional debe referirse a su lado propietario (Entidad que contiene la clave extranjera) utilizando el elemento
mappedBy
de la anotación@OneToOne
,@OneToMany
, o@ManyToMany
. El elementomappedBy
designa la propiedad o campo de la entidad propietaria de la relación. - El lado múltiple de las relaciones bidireccionales
@ManyToOne
no debe definir el elementomappedBy
. El lado many es siempre el lado propietario de la relación. - Para las relaciones bidireccionales
@OneToOne
, el lado propietario corresponde al lado que contiene @JoinColumn, es decir, la clave externa correspondiente. - Para las relaciones bidireccionales
@ManyToMany
, cualquiera de los lados puede ser el lado propietario.
@OneToMany relationship with JPA and Hibernate
Simplemente, el mapeo uno-a-muchos significa que una fila en una tabla se mapea a múltiples filas en otra tabla.
Cuándo utilizar el mapeo uno a muchos
Utilizar el mapeo uno a uno para crear 1…N relación entre entidades u objetos.
Tenemos que escribir dos entidades es decir.
Company
yBranch
de tal forma que se puedan asociar múltiples sucursales a una sola empresa, pero una sola sucursal no puede ser compartida entre dos o más empresas.
Soluciones de mapeo de uno a varios en Hibernate:
- Mapeo de uno a varios con asociación de clave foránea
- Mapeo de uno a varios con tabla de unión
Este problema se puede resolver de dos maneras diferentes.
Una es tener una columna de clave foránea en la tabla de sucursales, es decir,
company_id
. Esta columna se referirá a la clave primaria de la tabla Empresa. De esta manera no hay dos rama puede ser asociado con múltiples company.Segundo enfoque es tener una tabla de unión común digamos
Company_Branch,
Esta tabla tendrá dos columnas es decir,company_id
que será clave externa que se refiere a la clave primaria en la tabla de la empresa y de manera similarbranch_id
que será clave externa que se refiere a la clave primaria de la tabla Branch.
Si @OneToMany/@ManyToOne no tiene una asociación @ManyToOne/@OneToMany en el lado hijo, entonces, la asociación @OneToMany/@ManyToOne es unidireccional.
@OneToMany Unidirectional Relationship
En este enfoque, cualquier entidad será responsable de hacer la relación y mantenerla. O bien la empresa declara la relación como uno a muchos, o la sucursal declara la relación desde su extremo como muchos a uno.
CASO 1: (Mapeo con asociación de clave foránea)
Si usamos sólo @OneToMany
entonces habrá 3 tablas. Como company
, branch
y company_branch.
NOTA:
En el ejemplo anterior he utilizado términos como cascada, orphanRemoval, fetch y targetEntity, que explicaré en mi próximo post.
La tabla company_branch
tendrá dos claves foráneas company_id
y branch_id
.
Ahora, si persistimos una Empresa y dos Sucursales:
Hibernate va a ejecutar las siguientes sentencias SQL:
- La asociación
@OneToMany
es por definición una asociación padre(no propietaria), aunque sea unidireccional o bidireccional. Sólo el lado del padre de una asociación tiene sentido para la cascada de sus transiciones de estado de la entidad a los hijos. - Al persistir la entidad
Company
, la cascada propagará la operación de persistencia a los hijos de la rama subyacente también. Al eliminar unBranch
de la colección de ramas, la fila de la asociación se elimina de la tabla de enlaces, y el atributoorphanRemoval
desencadenará una eliminación de la rama también.
Las asociaciones unidireccionales no son muy eficientes cuando se trata de eliminar entidades hijas. En este ejemplo concreto, al vaciar el contexto de persistencia, Hibernate elimina todas las entradas hijas de la base de datos y reinserta las que aún se encuentran en el contexto de persistencia en memoria.
En cambio, una asociación bidireccional @OneToMany
es mucho más eficiente porque la entidad hija controla la asociación.
CASO 2: (Mapeo con asociación de clave foránea)
Si utilizamos sólo @ManyToOne
entonces habrá 2 tablas. Como empresa, sucursal.