Spring Boot

SpringBoot

Tutorial SpringBoot: Asociaciones de entidades JPA

Spring Boot entidades JPA asociaciones: mapeo. Aprende a mapear entidades JPA con asociaciones en Spring Boot con ejemplos prácticos.

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.

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.

Certifícate en SpringBoot con CertiDevs PLUS

Ejercicios de esta lección Asociaciones de entidades JPA

Evalúa tus conocimientos de esta lección Asociaciones de entidades JPA con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Web y Test Starters

Spring Boot
Puzzle

Entidades JPA

Spring Boot
Test

Repositorios reactivos

Spring Boot
Test

Inserción de datos

Spring Boot
Test

Borrar datos de base de datos

Spring Boot
Test

Controladores Spring MVC

Spring Boot
Código

Backend API REST con Spring Boot

Spring Boot
Proyecto

Operadores Reactivos

Spring Boot
Puzzle

Controladores Spring REST

Spring Boot
Código

Uso de Spring con Thymeleaf

Spring Boot
Puzzle

Crear entidades JPA

Spring Boot
Código

Registro de usuarios

Spring Boot
Test

CRUD y JPA Repository

Spring Boot
Puzzle

Anotaciones y mapeo en JPA

Spring Boot
Puzzle

Integración con Vue

Spring Boot
Test

Consultas JPQL con @Query en Spring Data JPA

Spring Boot
Test

Open API y cómo agregarlo en Spring Boot

Spring Boot
Puzzle

Uso de Controladores REST

Spring Boot
Puzzle

API Specification

Spring Boot
Puzzle

Inyección de dependencias

Spring Boot
Test

Introducción a Spring Boot

Spring Boot
Test

Consultas JPQL con @Query en Spring Data JPA

Spring Boot
Puzzle

API Query By Example (QBE)

Spring Boot
Puzzle

Inyección de dependencias

Spring Boot
Código

Vista en Spring MVC con Thymeleaf

Spring Boot
Test

Servicios en Spring

Spring Boot
Código

Configuración de Vue

Spring Boot
Puzzle

Integración con Angular

Spring Boot
Test

API Query By Example (QBE)

Spring Boot
Test

API Specification

Spring Boot
Test

Controladores MVC

Spring Boot
Test

Métodos find en repositorios

Spring Boot
Test

Repositorios Spring Data

Spring Boot
Test

Inyección de dependencias

Spring Boot
Puzzle

Data JPA y Mail Starters

Spring Boot
Test

Configuración de Angular

Spring Boot
Puzzle

Controladores Spring REST

Spring Boot
Test

Configuración de Controladores MVC

Spring Boot
Puzzle

Asociaciones de entidades JPA

Spring Boot
Código

Actualizar datos de base de datos

Spring Boot
Test

Identificadores y relaciones JPA

Spring Boot
Puzzle

Verificar token JWT en peticiones

Spring Boot
Test

Login de usuarios

Spring Boot
Test

Integración con React

Spring Boot
Test

Configuración de React

Spring Boot
Puzzle

Asociaciones en JPA

Spring Boot
Test

Consultas JPQL

Spring Boot
Código

Todas las lecciones de SpringBoot

Accede a todas las lecciones de SpringBoot y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Spring Boot

Spring Boot

Introducción Y Entorno

Spring Boot Starters

Spring Boot

Introducción Y Entorno

Inyección De Dependencias

Spring Boot

Introducción Y Entorno

Controladores Spring Mvc

Spring Boot

Spring Web

Vista En Spring Mvc Con Thymeleaf

Spring Boot

Spring Web

Controladores Spring Rest

Spring Boot

Spring Web

Open Api Y Cómo Agregarlo En Spring Boot

Spring Boot

Spring Web

Servicios En Spring

Spring Boot

Spring Web

Crear Entidades Jpa

Spring Boot

Persistencia Con Spring Data

Asociaciones De Entidades Jpa

Spring Boot

Persistencia Con Spring Data

Repositorios Spring Data

Spring Boot

Persistencia Con Spring Data

Métodos Find En Repositorios

Spring Boot

Persistencia Con Spring Data

Inserción De Datos

Spring Boot

Persistencia Con Spring Data

Actualizar Datos De Base De Datos

Spring Boot

Persistencia Con Spring Data

Borrar Datos De Base De Datos

Spring Boot

Persistencia Con Spring Data

Consultas Jpql Con @Query En Spring Data Jpa

Spring Boot

Persistencia Con Spring Data

Api Query By Example (Qbe)

Spring Boot

Persistencia Con Spring Data

Repositorios Reactivos

Spring Boot

Persistencia Con Spring Data

Api Specification

Spring Boot

Persistencia Con Spring Data

Integración Con React

Spring Boot

Integración Frontend

Integración Con Vue

Spring Boot

Integración Frontend

Integración Con Angular

Spring Boot

Integración Frontend

Registro De Usuarios

Spring Boot

Seguridad Con Spring Security

Login De Usuarios

Spring Boot

Seguridad Con Spring Security

Verificar Token Jwt En Peticiones

Spring Boot

Seguridad Con Spring Security

En esta lección

Objetivos de aprendizaje 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.