¡AYUDA! No se fijan las relaciones (OneToMany)

¿Haces un persist de un OneToMany pero luego tu lista te sale vacía? Mira este vídeo porque puede que estés estableciendo mal las relaciones en tu setter. En este vídeo te explico cómo puedes solucionarlo.

Este curso ha sido marcado como anticuado y no está siendo revisado de forma activa. Es posible que la información pueda estar desactualizada o que los enlaces se hayan roto.

Cuando trabajamos con JPA y bases de datos H2, es fundamental entender cómo se almacenan realmente los datos y cómo manejar correctamente las relaciones entre entidades, especialmente las de tipo uno a muchos. Para empezar, podemos configurar nuestro persistence.xml para que los datos se guarden en un archivo, lo que nos permite inspeccionarlos fácilmente usando la consola de H2. Al ejecutar nuestra aplicación y detenerla para evitar conflictos de acceso concurrente, podemos conectarnos a la consola y observar cómo se crean las tablas, por ejemplo, autores y libros. Allí veremos que los datos se almacenan tal y como esperamos, con autores y sus respectivos libros relacionados mediante claves foráneas.

Sin embargo, el verdadero desafío aparece cuando manipulamos relaciones bidireccionales en JPA. En Java, aunque el lenguaje es orientado a objetos, hay ciertas responsabilidades que recaen sobre nosotros como desarrolladores para mantener sincronizadas ambas partes de la relación. Por ejemplo, si tenemos un autor y una lista de libros, no basta con asignar la lista de libros al autor mediante un método setLibros. Es crucial que cada libro también conozca quién es su autor, porque es el libro quien mantiene la columna de unión (join column) en la base de datos.

Si solo actualizamos la lista de libros en el autor sin informar a cada libro de su autor, JPA no podrá persistir correctamente la relación. Esto se traduce en que, al guardar y luego recuperar los datos, la relación no se reflejará como esperamos. Para solucionar esto, podemos modificar el método setLibros para que, además de asignar la lista, recorra cada libro y establezca su autor apuntando a la instancia actual. De esta forma, aseguramos que ambas entidades están sincronizadas.

Otra estrategia más elegante es crear un método auxiliar, por ejemplo hazLibro, que añada un libro a la lista del autor y, simultáneamente, establezca el autor en el libro. Así evitamos manipular directamente la lista desde fuera y mantenemos la lógica de sincronización encapsulada.

public void hazLibro(Libro libro) {
    if (!libros.contains(libro)) {
        libros.add(libro);
        libro.setAutor(this);
    }
}

Además, es importante contemplar la desconexión de la relación. Si queremos eliminar un libro de un autor, debemos asegurarnos de que el libro también deje de referenciar a ese autor. Para ello, un método quitarLibro puede encargarse de eliminar el libro de la lista y poner su autor a null.

public void quitarLibro(Libro libro) {
    if (libros.contains(libro)) {
        libros.remove(libro);
        libro.setAutor(null);
    }
}

No debemos confiar únicamente en las opciones de cascada (cascade) para resolver este problema, ya que estas no sustituyen la necesidad de mantener ambas partes de la relación informadas. Java y JPA esperan que nosotros gestionemos explícitamente estas conexiones para que la persistencia funcione correctamente.

Este patrón de mantener sincronizadas ambas entidades no es exclusivo de JPA ni de bases de datos relacionales; si estuviéramos trabajando con estructuras en memoria o archivos, también tendríamos que asegurarnos de que las referencias entre objetos estén correctamente actualizadas para evitar inconsistencias.

Por último, si estáis trabajando con relaciones más complejas, como many-to-many, o queréis profundizar en otros errores comunes, es buena idea plantear vuestras dudas y temas de interés para seguir aprendiendo juntos y resolver esos retos que surgen al manejar ORM en Java.

Lista de reproducción
  1. 1
    La persistencia es clave
    6 minutos
  2. 2
    Instalando Hibernate
    8 minutos
  3. 3
    Crear el persistence.xml
    9 minutos
  4. 4
    Construyendo una Entity
    8 minutos
  5. 5
    Accediendo al EntityManager
    9 minutos
  6. 6
    Insertando con persist
    7 minutos
  7. 7
    Managed Entities
    6 minutos
  8. 8
    Merge y remove
    5 minutos
  9. 9
    Inciso sobre Java 8
    7 minutos
  10. 10
    Introducción a relaciones
    6 minutos
  11. 11
    Relación OneToOne
    11 minutos
  12. 12
    OneToOne inverso con mappedBy
    8 minutos
  13. 13
    OneToMany: planteamiento
    6 minutos
  14. 14
    OneToMany: anotaciones
    6 minutos
  15. 15
    OneToMany: EntityManager
    7 minutos
  16. 16
    ¡AYUDA! Error Lazy Initialization (OneToMany)
    5 minutos
  17. 17
    ¡AYUDA! No se fijan las relaciones (OneToMany)
    8 minutos
  18. 18
    Borrar hijos en un OneToMany
    11 minutos
  19. 19
    ON DELETE SET NULL
    8 minutos