Asociaciones de entidades JPA

Intermedio
SpringBoot
SpringBoot
Hoy: 01/07/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

Las asociaciones de Entidades JPA (Java Persistence API) son una funcionalidad que permite representar relaciones entre distintas tablas en una base de datos en el nivel de las clases de Java.

¿Te está gustando esta lección?

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Esto significa que podemos relacionar clases de Java por medio de Composición y en base de datos se generen claves foráneas apuntando a claves primarias, de modo que las tablas estén relacionadas.

Las asociaciones de Entidades pueden ser de varios tipos, dependiendo de cómo se relacionan las entidades entre sí. Estas pueden ser:

  • uno a uno (One-to-One)
  • uno a muchos (One-to-Many)
  • muchos a uno (Many-to-One)
  • muchos a muchos (Many-to-Many)

One-to-One (Uno a Uno)

La relación One-to-One indica que una instancia de una entidad A sólo puede estar asociada con una única instancia de otra entidad B, y viceversa.

En otras palabras, hay una correspondencia uno a uno entre las entidades.

Por ejemplo, consideremos una aplicación donde cada User tiene un único Profile, y cada Profile pertenece a un único User.

En este caso, la relación entre User y Profile es One-to-One.

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;


    @JoinColumn(name = "profile_id", unique = true)
    private Profile profile;
}

@Entity
public class Profile {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToOne(mappedBy = "profile")
    private User user;
}

La anotación @JoinColumn se utiliza para especificar la columna que será usada para unir la tabla actual con la tabla referenciada. En este caso, se utiliza en la clase Comment para establecer una relación con Post:

Por otro lado, mappedBy se utiliza en el lado "no propietario" (en inglés "non-owning side") de la relación para especificar el campo dentro de la entidad propietaria (en inglés "owning side") que controla la relación:

Aquí, mappedBy = "profile" indica que la propiedad profile en la clase User es el lado "propietario" de la relación. Esto significa que cualquier cambio realizado en el campo profile de un objeto User se reflejará en la base de datos. Pero no al revés.

One-to-Many / Many-to-One (Uno a Muchos / Muchos a Uno)

La relación One-to-Many indica que una instancia de una entidad A puede estar asociada con múltiples instancias de otra entidad B, pero cada instancia de B está asociada con un único A.

Desde la perspectiva de B a A, esta relación es Many-to-One.

Por ejemplo, supongamos que en una aplicación de blog, un Post puede tener múltiples Comment, pero cada Comment pertenece a un único Post. Aquí, la relación entre Post y Comment es One-to-Many.

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
    private List<Comment> comments;
}

@Entity
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;
}

En una relación bidireccional, como @OneToMany y @ManyToOne, se debe designar un lado como el "propietario" de la relación.

El lado propietario es el que controla la actualización de la relación entre las dos entidades. En este caso, Comment es la entidad propietaria porque contiene el campo @JoinColumn. Esto significa que si quieres crear, actualizar o eliminar una relación entre un Post y un Comment, deberás hacerlo desde el lado de Comment.

Por ejemplo, si tienes un Post y quieres añadirle un nuevo Comment, normalmente lo harías de la siguiente manera:

Post post = new Post();
Comment comment1 = new Comment();
Comment comment2 = new Comment();

comment1.setPost(post);
comment2.setPost(post);

post.setComments(Arrays.asList(comment1, comment2));

Al guardar comment1 y comment2, la relación se reflejará en la base de datos porque Comment es el lado propietario de la relación.

Many-to-Many (Muchos a Muchos)

La relación Many-to-Many indica que múltiples instancias de una entidad A pueden estar asociadas con múltiples instancias de otra entidad B.

Por ejemplo, en un sistema de gestión de universidades, un Student puede estar inscrito en múltiples Course, y un Course puede tener múltiples Student inscritos. En este caso, la relación entre Student y Course es Many-to-Many.

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToMany
    @JoinTable(name = "student_course",
        joinColumns = @JoinColumn(name = "student_id"),
        inverseJoinColumns = @JoinColumn(name = "course_id"))
    private List<Course> courses;
}

@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToMany(mappedBy = "courses")
    private List<Student> students;
}

En cada uno de estos casos, se utilizan anotaciones específicas de JPA para definir la relación y las propiedades correspondientes de las entidades involucradas. En las relaciones Many-to-Many, se utiliza la anotación @JoinTable para definir la tabla de enlace que maneja la asociación entre las entidades.

En este caso, como la clase Student es quien tiene la anotación @JoinTable dentro, será el lado propietario (owner) por lo que para guardar la relación en base de datos será necesario añadir courses al listado de courses de un Student y persistirlo en base de datos.

Cascada y Fetch

Las operaciones de cascada y las estrategias de carga (fetch) son dos aspectos fundamentales de las relaciones entre entidades en JPA.

Cascada

Las operaciones en cascada son aquellas operaciones que se propagan de una entidad a las entidades relacionadas. Por ejemplo, si se guarda una entidad, y esta tiene una relación en cascada con otras entidades, entonces todas estas entidades se guardarán también.

Las operaciones de cascada disponibles en JPA son:

  • CascadeType.PERSIST: Cascada la operación persist (guardar). Si guardas la entidad fuente, las entidades relacionadas también se guardarán.
  • CascadeType.REMOVE: Cascada la operación remove (eliminar). Si eliminas la entidad fuente, las entidades relacionadas también se eliminarán.
  • CascadeType.REFRESH: Cascada la operación refresh (refrescar). Si refrescas la entidad fuente, las entidades relacionadas también se refrescarán.
  • CascadeType.MERGE: Cascada la operación merge (fusionar). Si fusionas la entidad fuente, las entidades relacionadas también se fusionarán.
  • CascadeType.DETACH: Cascada la operación detach (desconectar). Si desconectas la entidad fuente, las entidades relacionadas también se desconectarán.
  • CascadeType.ALL: Cascada todas las operaciones anteriores. Si cualquier operación se realiza en la entidad fuente, la misma operación se propagará a las entidades relacionadas.

Aquí hay un ejemplo de cómo se utiliza:

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
    private List<Comment> comments;
}

En este ejemplo, si un Post se elimina, todos los Comment asociados también se eliminarán de la base de datos. Esto es porque la operación remove se propaga desde Post a Comment debido a la configuración CascadeType.ALL.

Fetch

Fetch se refiere a cuándo se deben cargar los datos de las entidades relacionadas desde la base de datos. JPA ofrece dos estrategias de carga: EAGER y LAZY.

  • FetchType.EAGER: Este tipo de carga significa que las entidades relacionadas se cargan al mismo tiempo que la entidad fuente. Por ejemplo, si se carga un Post desde la base de datos, todos los Comment asociados también se cargan al mismo tiempo.
  • FetchType.LAZY: Este tipo de carga significa que las entidades relacionadas se cargan a demanda, es decir, cuando se accede a ellas por primera vez. Por ejemplo, si se carga un Post, los Comment asociados no se cargarán hasta que se acceda a ellos mediante post.getComments().

Aquí hay un ejemplo de cómo se utiliza:

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
    private List<Comment> comments;
}

En este ejemplo, los Comment asociados a un Post no se cargarán de la base de datos hasta que se invoque post.getComments().

La elección de las estrategias de cascada y carga depende de las necesidades específicas de la aplicación y de las consideraciones de rendimiento.

Conclusión

En conclusión, las asociaciones de entidades JPA en Spring Boot proporcionan una forma poderosa y flexible de mapear las relaciones entre las entidades de la base de datos en un modelo de objetos de dominio. Estas asociaciones pueden representar diversas relaciones como One-to-One, One-to-Many, Many-to-One y Many-to-Many.

Las anotaciones como @OneToOne, @OneToMany, @ManyToOne, @ManyToMany, @JoinColumn, @JoinTable, entre otras, facilitan la configuración de estas relaciones. Además, JPA ofrece operaciones en cascada que permiten propagar ciertas operaciones desde una entidad a sus entidades relacionadas, lo que facilita el manejo de las operaciones de base de datos.

Además, JPA proporciona estrategias de carga EAGER y LAZY para optimizar el rendimiento de la base de datos. La estrategia EAGER carga las entidades relacionadas inmediatamente, mientras que la estrategia LAZY las carga a demanda, lo que puede ayudar a mejorar la eficiencia de la aplicación.

Aprendizajes de esta lección

  1. Entender las diferentes tipos de relaciones entre entidades: One-to-One, One-to-Many, Many-to-One y Many-to-Many.
  2. Aprender a usar las anotaciones para mapear las relaciones entre entidades.
  3. Conocer cómo se manejan las operaciones en cascada para propagar operaciones desde una entidad a otras relacionadas.
  4. Comprender las estrategias de carga EAGER y LAZY para optimizar el rendimiento de la base de datos.
  5. Aplicar las asociaciones de entidades JPA en un proyecto Spring Boot real.

Completa SpringBoot y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración