String
, pero nuestros objetos de negocio muchas veces tienen relaciones con otros objetos con un campo de su tipo o incluso contienen una lista de ellos.En esta entrada nos vamos a centrar en objetos que tengan una lista de entidades lo que forma una relación "Uno a Muchos" que en JPA se conoce con la anotación
@OneToMany
o la etiqueta one-to-many
(y viceversa @ManyToOne
).La relación con
@OneToMany
puede hacerse con una Join Table o con una clave ajena en la tabla de entidades del tipo contenido en la lista (Join Column). En esta entrada se va a ver esto último.Para verlo voy a usar la clase
Partido
de datos-deportivos
, ya que tiene una Collection<Suceso>
que hereda de EventoImpl
.Lo primero que tenemos que hacer es implementar un código necesario previo para centrarnos después en el objeto de esta entrada. El código está en el commit previo a empezar con la definición de estas relaciones y contiene:
- Creación de sendas clases entidad para
Partido
(PartidoConId
) ySuceso
(SucesoConId
) ya que estos tipos no tienen ningún campo que pueda usarse comoId
y todas las entidades lo necesitan. - En este caso los Ids serán autogenerados por la base de datos con
@GeneratedValue
eIDENTITY
. - Como todos los tipos de los que heredan
Partido
ySuceso
son de una librería de terceros tengo que usar la configuración XML porque no puedo anotar los campos. - Una vez creados los ficheros ORM hay que añadirlos a la configuración.
Usando nuestros conocimientos de modelado de datos vamos a representar la relación
PartidoConId-SucesoConId
añadiendo a la tabla de Suceso
s la clave ajena (FK) de PartidoConId
al que pertenece ese Suceso
.Para ello definimos con la etiqueta
one-to-many
el nombre de nuestro campo con la colección de Suceso
s, el tipo de entidad destino (SucesoConId
) y con qué campo se mapea (con partido - veremos qué significa esto más abajo). Usamos la siguiente etiqueta dentro de los atributos de EventoImpl
:<one-to-many name="sucesos" target-entity="es.lanyu.eventos.repositorios.SucesoConId" mapped-by="partido"/>
NOTA: Es importante destacar que el tipo objetivo debe ser una entidad, no vale con la interface
Suceso
, debe ser la entidad SucesoConId
.
Al hacerlo de esta forma (usando una FK en una Join Column) la relación debe ser bidireccional: se puede navegar de
Partido
a Suceso
y viceversa. Esto implica que nuestra clase SucesoConId
tiene que añadir un campo partido
para saber cómo se mapea esa FK. Este campo debe tener el nombre que hemos puesto en mapped-by="partido"
y ser del tipo de la entidad que contiene la colección (PartidoConId
).PartidoConId partido;
public PartidoConId getPartido() {
return partido;
}
public void setPartido(PartidoConId partido) {
this.partido = partido;
}
Además se deben añadir los respectivos accesores (getter/setter) para este campo. Esto se debe a que hay que mantener sincronizadas las dos entidades cuando se modifique (añadir en PartidoConId
otro Suceso
):public void addSucesoConId(SucesoConId suceso) {
super.addSuceso(suceso);
suceso.setPartido(this);
}
Por último, debemos añadir en nuestro ORM para SucesoConId
la etiqueta many-to-one
para cerrar la relación en los dos sentidos e indicar la columna que se usa para hacer el join:<many-to-one name="partido" optional="false"><!-- fetch="LAZY">-->
<join-column name="ID_PARTIDO" referencedColumnName="ID"/>
</many-to-one>
NOTA: Dejo comentado el atributo
fetch="LAZY"
para ver cómo se pondría si se quisiera que la relación no se traiga los datos hasta que no se necesiten.
En el código hasta aquí se puede encontrar comentadas las anotaciones que corresponden a esta configuración XML en
SucesoConId
. Sin embargo, podemos ver que seríamos incapaces de añadírselo a EventoImpl
al no ser código que gestionemos nosotros.Todo esto puede verse funcionando en el video anterior con un
main
modificado que irá insertando partidos con un suceso y lo imprime para ver el resultado.
No hay comentarios:
Publicar un comentario