Saltar al contenido principal

JPA y Hibernate

Mapeo Objeto-Relacional (ORM) y Entidades

Para interactuar con bases de datos relacionales en aplicaciones Java modernas se utilizan tecnologías ORM (Object-Relational Mapping), las cuales traducen las clases y objetos del lenguaje a tablas y filas en el motor de base de datos.


1. Diferencia entre JPA y Hibernate​

Existe una distinción fundamental entre la especificación y su implementación concreta:

Clic para ampliar
Explicación Detallada del Diagrama de Persistencia
  1. JPA (Jakarta Persistence API): Es una especificación del lenguaje Java (un conjunto de interfaces del paquete jakarta.persistence.* como @Entity, @Id, @Column). JPA no contiene lógica ejecutable; simplemente define el estándar de anotaciones y contratos.
  2. Hibernate ORM: Es la implementación concreta (el motor) elegida por defecto en Spring Boot. Lee las anotaciones de JPA, traduce las operaciones de objetos a sintaxis SQL según el dialecto configurado y administra la sesión de persistencia.
  3. Base de Datos Relacional: Es el motor físico donde residen los datos tabulares.

2. Mapeo de Entidades JPA y sus Anotaciones​

Una Entidad es una clase POJO (Plain Old Java Object) que representa una tabla en la base de datos. Cada instancia de la clase corresponde a una fila en la tabla.

2.1. Anotaciones de Mapeo Fundamental​

AnotaciónPropósitoAtributos Comunes
@EntityDeclara que la clase Java es una entidad administrada por JPA.name (nombre lógico de la entidad en JPQL)
@TableEspecifica la tabla física en la base de datos.name, schema, uniqueConstraints
@IdMarca un atributo como la clave primaria (Primary Key).N/A
@GeneratedValueEspecifica la estrategia de generación automática de la clave primaria.strategy (IDENTITY, SEQUENCE, AUTO, TABLE)
@ColumnConfigura los detalles de mapeo de la columna física.name, nullable, unique, length, precision
@JoinColumnDefine la columna de clave foránea (Foreign Key) en relaciones.name, referencedColumnName, nullable
@TransientIndica que el atributo no debe persistirse en la base de datos.N/A

3. Modelo de Base de Datos Relacional (Diagrama ER)​

Antes de escribir el código en Java, visualizamos el diseño del esquema relacional de la base de datos para un dominio de catálogo de productos:

Clic para ampliar
Explicación Detallada del Diagrama Entidad-Relación
  • CATEGORIAS: Tabla padre que almacena la clasificación del producto. Relación 1 a N con PRODUCTOS.
  • PROVEEDORES: Tabla padre que representa la empresa suministradora. Relación 1 a N con PRODUCTOS.
  • PRODUCTOS: Tabla principal que contiene dos Claves Foráneas (FK): categoria_id y proveedor_id, las cuales enlazan físicamente hacia las claves primarias (PK) de las tablas padres.

4. Mapeo Completo en Código Java con JPA y Lombok​

A continuación se traduce el diagrama ER a código de entidades Java utilizando anotaciones de JPA y Lombok:

4.1. Entidad Category (Tabla categorias)​

src/main/java/com/icesi/app/model/Category.java
package com.icesi.app.model;

import jakarta.persistence.*;
import lombok.*;

// Marca la clase como Entidad administrada por el contexto de JPA
@Entity
// Define el nombre físico de la tabla en la base de datos relacional
@Table(name = "categorias")
// Lombok: Genera métodos de lectura Getters para todos los campos
@Getter
// Lombok: Genera métodos de modificación Setters para todos los campos
@Setter
// Lombok: Constructor vacío obligatorio requerido por el motor de reflexión de JPA
@NoArgsConstructor
// Lombok: Constructor completo con todos los atributos
@AllArgsConstructor
// Lombok: Construcción fluida de instancias mediante el patrón Builder
@Builder
public class Category {

// Define la clave primaria (Primary Key)
@Id
// Estrategia IDENTITY: Delega la autogeneración al campo AUTO_INCREMENT/SERIAL de la BD
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

// Columna obligatoria (NOT NULL) con longitud máxima de 80 caracteres
@Column(name = "nombre", nullable = false, length = 80)
private String name;

// Columna opcional de descripción detallada
@Column(name = "descripcion", length = 255)
private String description;
}

4.2. Entidad Supplier (Tabla proveedores)​

src/main/java/com/icesi/app/model/Supplier.java
package com.icesi.app.model;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "proveedores")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Supplier {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

// Nombre comercial de la empresa proveedora
@Column(name = "nombre_empresa", nullable = false, length = 100)
private String companyName;

// Número de identificación tributaria (único en la base de datos)
@Column(name = "nit_ruc", unique = true, nullable = false, length = 50)
private String taxId;
}

4.3. Entidad Product con Relaciones @ManyToOne (Tabla productos)​

src/main/java/com/icesi/app/model/Product.java
package com.icesi.app.model;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "productos")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Product {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

// Nombre del producto no nulo con límite de 120 caracteres
@Column(name = "nombre_producto", nullable = false, length = 120)
private String name;

// Precio unitario del producto
@Column(name = "precio", nullable = false, precision = 10, scale = 2)
private Double price;

// Código SKU único de inventario
@Column(name = "codigo_sku", unique = true, nullable = false, length = 50)
private String sku;

// Campo calculado o temporal en memoria (JPA ignorará este campo y NO creará columna en la BD)
@Transient
private String temporaryDiscountCode;

// ==========================================
// MAPEO DE RELACIONES RELACIONALES (FOREIGN KEYS)
// ==========================================

// Relación N:1 -> Muchos productos pertenecen a una Categoría
// FetchType.LAZY evita cargar la categoría de la BD hasta que sea explícitamente consultada
@ManyToOne(fetch = FetchType.LAZY)
// Especifica la columna de clave foránea (Foreign Key) 'categoria_id' en la tabla 'productos'
@JoinColumn(name = "categoria_id", nullable = false)
private Category category;

// Relación N:1 -> Muchos productos son suministrados por un Proveedor
@ManyToOne(fetch = FetchType.LAZY)
// Especifica la columna de clave foránea (Foreign Key) 'proveedor_id' en la tabla 'productos'
@JoinColumn(name = "proveedor_id", nullable = false)
private Supplier supplier;
}

Cuestionario de Autoevaluación​

Cargando cuestionario...