Translate

Mostrando las entradas con la etiqueta JPA. Mostrar todas las entradas
Mostrando las entradas con la etiqueta JPA. Mostrar todas las entradas

lunes, 7 de julio de 2025

Mapeo de Herencia en JPA


JPA ofrece 3 estrategias para mapear herencia:

  • @Inheritance(strategy = SINGLE_TABLE) : Todo se guarda en una sola tabla con una columna discriminadora. 
  • @Inheritance(strategy = JOINED): Se usa una tabla por clase, relacionadas por claves foráneas.        
  • @Inheritance(strategy = TABLE_PER_CLASS): Una tabla para cada clase, sin relaciones.                           

Veamos un ejemplo: Clase base y subclases

Vamos a usar la estrategia: SINGLE_TABLE.


package com.ejemplo.demo.entidad;

import jakarta.persistence.*;


@Entity

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

@DiscriminatorColumn(name = "tipo_empleado", discriminatorType = DiscriminatorType.STRING)

public abstract class Empleado {


    @Id

    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;

    private String nombre;


    // Getters y setters

}


@Inheritance(...): Define la estrategia de herencia.

@DiscriminatorColumn(...):  Crea una columna adicional (tipo_empleado) que almacena el tipo real de cada instancia.


📄 Gerente.java


package com.ejemplo.demo.entidad;


import jakarta.persistence.*;


@Entity

@DiscriminatorValue("GERENTE")

public class Gerente extends Empleado {


    private String departamento;


    // Getters y setters

}


📄 Desarrollador.java


package com.ejemplo.demo.entidad;


import jakarta.persistence.*;


@Entity

@DiscriminatorValue("DESARROLLADOR")

public class Desarrollador extends Empleado {


    private String lenguajeFavorito;


    // Getters y setters

}


Resultado en la base de datos


Se crea una única tabla empleado, con las columnas:

id, nombre, departamento, lenguajeFavorito y tipo_empleado (con valores como GERENTE, DESARROLLADOR)


Ventajas de SINGLE_TABLE

    • Más simple y rápida para consultas.

    • Ideal si la mayoría de los campos son comunes.

Desventajas

    • Muchos campos nulos en columnas que sólo usa una subclase.


Otras estrategias: 

    • JOINED: separa en tablas, y junta usando claves foráneas. Útil si los datos son muy distintos y no querés campos nulos.

    • TABLE_PER_CLASS: evita JOINs, pero no es tan usada. No permite relaciones polimórficas fácilmente.


domingo, 6 de julio de 2025

Relaciones entre Entidades con JPA


Aprender a modelar relaciones entre tablas en Java usando JPA, como por ejemplo:

  • @OneToMany (uno a muchos)

  • @ManyToOne (muchos a uno)

  • @OneToOne (uno a uno)

  • @ManyToMany (muchos a muchos)


En este ejemplo vamos a modelar una relación simple: Una Persona puede tener varias Direcciones.


package com.ejemplo.demo.entidad;


import jakarta.persistence.*;

import java.util.List;


@Entity

public class Persona {


@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Long id;

private String nombre;

@OneToMany(mappedBy = "persona", cascade = CascadeType.ALL, orphanRemoval = true)

private List<Direccion> direcciones;


// Constructores, getters y setters

}


Anotaciones clave:

@OneToMany(mappedBy = "persona"): Declara una relación de uno a muchos. Una persona puede tener varias direcciones.

  • mappedBy = "persona": indica que el atributo que mantiene la relación está del otro lado (Direccion.persona).
  • cascade = CascadeType.ALL: al guardar o eliminar una persona, se aplican los cambios también a sus direcciones.
  • orphanRemoval = true: elimina direcciones si se quitan de la lista.



Entidad Direccion:



package com.ejemplo.demo.entidad;


import jakarta.persistence.*;


@Entity

public class Direccion {


@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Long id;

private String calle;

private String ciudad;


@ManyToOne

@JoinColumn(name = "persona_id")

private Persona persona;


// Constructores, getters y setters

}



Anotaciones clave:

@ManyToOne: Cada dirección pertenece a una sola persona.

@JoinColumn(name = "persona_id"): Crea una columna en la tabla direccion llamada persona_id que actúa como clave foránea a la tabla persona.


Las listas deben ser inicializadas como new ArrayList<>() si se van a usar directamente.

Si no usás orphanRemoval, las direcciones quedan "huérfanas" si quitás una de la lista.


Un pequeño ejemplo para que vayamos incrementando nuestro conocimiento en JPA. 

miércoles, 2 de julio de 2025

¿Qué es Spring Data JPA? Parte 2

 


Veamos un ejemplo de entidad de jpa: 

📄 Persona.java


package com.ejemplo.demo.entidad;

import jakarta.persistence.*;


@Entity

public class Persona {

    @Id

    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;

    private String nombre;

    private String email;


    // Constructores

    public Persona() {}

    public Persona(String nombre, String email) {

        this.nombre = nombre;

        this.email = email;

    }


    // Getters y setters

    public Long getId() { return id; }

    public String getNombre() { return nombre; }

    public void setNombre(String nombre) { this.nombre = nombre; }

    public String getEmail() { return email; }

    public void setEmail(String email) { this.email = email; }

}


@Entity: Marca esta clase como una entidad JPA, lo que significa que será persistida en una tabla de la base de datos. El nombre de la tabla por defecto será el mismo que el nombre de la clase (persona en minúsculas).

@Id: Indica que el atributo id es la clave primaria de la entidad. Cada fila tendrá un valor único en esta columna.

@GeneratedValue(strategy = GenerationType.IDENTITY):  Especifica que el valor del campo id será generado automáticamente por la base de datos (usualmente como autoincremental).  Existen otras estrategias (AUTO, SEQUENCE, TABLE), pero IDENTITY es simple y efectiva para bases H2 o MySQL.


Repositorio

📄 PersonaRepository.java


package com.ejemplo.demo.repositorio;

import com.ejemplo.demo.entidad.Persona;

import org.springframework.data.jpa.repository.JpaRepository;


public interface PersonaRepository extends JpaRepository<Persona, Long> {

}


JpaRepository<Persona, Long>:  Es una interfaz de Spring Data que nos proporciona métodos CRUD listos para usar: findAll(), save(), deleteById(), etc.

Persona: el tipo de entidad

Long: el tipo de la clave primaria (id)

No se necesita ninguna anotación porque Spring escanea esta interfaz y genera una implementación automática.


Servicio

📄 PersonaService.java


@Service

public class PersonaService {

    // ...

}


@Service:  Marca esta clase como un componente de servicio, lo que permite que Spring la detecte y gestione como parte del contexto de la aplicación (inyección de dependencias, ciclo de vida, etc.).

Controlador

📄 PersonaController.java


@RestController

@RequestMapping("/personas")

public class PersonaController {

    // ...

}


    • @RestController:  Marca la clase como un controlador REST. Es equivalente a usar @Controller + @ResponseBody para cada método.

    • @RequestMapping("/personas"):  Define la ruta base de la API. Todos los métodos se expondrán bajo /personas.

    • @GetMapping, @PostMapping, @DeleteMapping: Indican qué método HTTP debe usarse para cada operación.

    • @RequestBody:  Indica que los datos del cuerpo del request (formato JSON) deben ser convertidos a un objeto Java.

    • @PathVariable: Extrae una variable de la URL, por ejemplo /personas/1 extrae el id = 1.


Archivo application.properties

spring.datasource.url=jdbc:h2:mem:testdb

spring.jpa.hibernate.ddl-auto=update

spring.h2.console.enabled=true


spring.jpa.hibernate.ddl-auto=update:  Le indica a JPA que genere automáticamente las tablas según nuestras entidades. Si la tabla no existe, la crea.


martes, 1 de julio de 2025

¿Qué es Spring Data JPA?


JPA (Java Persistence API) es una especificación estándar de Java para el mapeo objeto-relacional (ORM), que permite interactuar con bases de datos relacionales utilizando objetos Java.


Con JPA se pueden:

    • Definir clases Java como entidades persistentes (@Entity).

    • Especificar relaciones entre entidades (uno a muchos, muchos a muchos, etc.).

    • Realizar operaciones como insertar, actualizar, eliminar y consultar datos sin escribir SQL explícito.


JPA no es una implementación, sino una interfaz estándar. Las implementaciones más comunes son:

    • Hibernate (la más usada)

    • EclipseLink

    • OpenJPA


Spring Data JPA es un módulo de Spring que simplifica el uso de JPA:

    • Permite definir interfaces de repositorio sin necesidad de implementar los métodos CRUD.

    • Integra la capa de persistencia con el resto del ecosistema de Spring (inyección de dependencias, control transaccional, validaciones, etc.).

    • Facilita la creación de consultas con nombres de método (findByNombre, findByEmailContaining, etc.).

    • Soporta JPQL, SQL nativo y consultas dinámicas.


Spring Data JPA es una abstracción sobre JPA que reduce drásticamente el código necesario para acceder a la base de datos.


Ventajas de usar JPA con Spring

    • Menos código repetitivo: no es necesario implementar manualmente métodos CRUD.

    • Integración total con Spring: todo se gestiona mediante inyección de dependencias y configuración automática.

    • Consultas declarativas: se pueden crear consultas complejas usando el nombre del método.

    • Abstracción del SQL: permite trabajar con objetos sin escribir sentencias SQL directamente.

    • Gestión automática del contexto de persistencia: Spring gestiona transacciones, apertura y cierre de conexiones.

    • Compatible con múltiples bases de datos: MySQL, PostgreSQL, H2, Oracle, SQL Server, etc.


En el siguiente post vamos con algo más práctico. 


miércoles, 23 de noviembre de 2022

Libros de Java Code Geeks

 

Download FREE IT Guides!

 

JVM Troubleshooting Guide

The Java bytecode produced when application are compiled, is eventually executed by the Java Virtual Machine (JVM). The JVM has grown to be a sophisticated tool, but it essentially...

 
 

Java 8 Features

With no doubts, Java 8 release is the greatest thing in the Java world since Java 5 (released quite a while ago, back in 2004). It brings tons of new features to the Java as a language,...

 
 

JPA Mini Book

One of the problems of Object Orientation is how to map the objects as the database requires. JPA allows us to work with Java classes as it provides a transparent layer to each database...

 
 

Spring Integration for EAI

It is a lightweight framework that builds upon the core Spring framework. It is designed to enable the development of integration solutions typical of event-driven architectures and...

 

jueves, 27 de octubre de 2022

Libros gratuitos de java code geeks

 

Get schooled by Java Code Geeks

Download FREE IT Guides!

 

Java Annotations Tutorial

We have provided an abundance of tutorials here at Java Code Geeks, like Creating Your Own Java Annotations, Java Annotations Tutorial with Custom Annotation and Java...

 
 

Spring Interview Questions

The majority of the things you may be asked is collected in the list below. All core modules, from basic Spring functionality such as Spring Beans, up to Spring MVC framework are...

 
 

Android UI Design

Android’s user interface is based on direct manipulation, using touch inputs that loosely correspond to real-world actions, like swiping, tapping, pinching and reverse pinching to...

 
 

JPA Minibook

The basic Java framework to access the database is JDBC. Unfortunately, with JDBC, a lot of hand work is needed to convert a database query result into Java classes. Other disadvantages...

 

martes, 21 de junio de 2022

Como chequear si un registro esta siendo cacheado por Hibernate en una aplicación Spring boot.


Necesitaba ver si un registro estaba siendo cacheado por hibernate es decir JPA, en una aplicación spring boot. 

Hice lo que cualquiera hubiera hecho, puse show-sql en true, corrí un test que busca 2 veces el registro y me fije en el log que no hubiera 2 selects. Fácil pero poco científico, estaría bueno hacer un test que pruebe esto, y bueno hice esto : 


@RunWith(SpringJUnit4ClassRunner::class)

@SpringBootTest(classes = [Application::class])

class EjemploRepositoryTest {


    @Autowired

    lateinit var ejemploRepository: EjemploRepository


    @Autowired

    lateinit var entityManagerFactory: EntityManagerFactory


    @Test

    fun `find a Ejemplo from Empty cache`() {

        val ejemplo= getEjemplo()

        val cache = entityManagerFactory.cache

        Assert.assertFalse(cache.contains(Ejemplo::class.java, ejemplo.id))

    }


    @Test

    fun `find a Ejemplo from cache`() {

        val ejemplo= getEjemplo()

        saveAndFind(ejemplo)


        val cache = entityManagerFactory.cache


        Assert.assertTrue(cache.contains(Ejemplo::class.java, ejemplo.id))

    }


    private fun saveAndFind(ejemplo: Ejemplo): Ejemplo{

        ejemploRepository.save(ejemplo)

        return ejemploRepository.findById(ejemplo.id).get()

    }


    private fun getEjemplo(): Ejemplo{

        return  ... //Aca construimos un ejemplo 

    }


}

Y listo!!

jueves, 24 de febrero de 2022

Libros Gratuitos de Java code Geeks

 

Download IT Guides!

 

JPA Minibook

The basic Java framework to access the database is JDBC. Unfortunately, with JDBC, a lot of hand work is needed to convert a database query result into Java classes. Other disadvantages...

 
 

Microservices for Java Developers

Microservices are a software development technique – a variant of the service-oriented architecture (SOA) structural style – that arranges an application as a collection of loosely...

 
 

JMeter Tutorial

JMeter is an application that offers several possibilities to configure and execute load, performance and stress tests using different technologies and protocols. It allows simulating...

 
 

Java Design Patterns

A design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be...

 

viernes, 24 de septiembre de 2021

Creando la primera aplicación con Quarkus parte 5


Seguimos con quarkus

Vamos a guardar unos saludos para luego poder recuperarlos y usarlos para saludar. 

Para esto vamos a crear una clase con el saludo : 

package com.hexacta.model;

import javax.persistence.*;
import java.util.Objects;

@Entity
public class Greeting {

@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
@Id
private Integer id;

@Column
private String value;

public void setId(Integer id) {
this.id = id;
}

public Integer getId() {
return id;
}

public Greeting() {}

public Greeting(String value) {
this.value = value;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Greeting greeting = (Greeting) o;
return Objects.equals(value, greeting.value);
}

@Override
public int hashCode() {
return Objects.hash(value);
}
}

Luego vamos a hacer una clase DAO para acceso a la base de datos : 

package com.hexacta.dao;

import com.hexacta.model.Greeting;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;

@ApplicationScoped
public class GreetingDAO {

@Inject
private EntityManager em;

public int save(Greeting aGreeting) {
this.em.persist(aGreeting);
return aGreeting.getId();
}

public Greeting get(int id) {
var qr = em.createQuery("from com.hexacta.model.Greeting g " +
"where g.id = ?1");
qr.setParameter(1, id);
return (Greeting) qr.getSingleResult();
}
}

Modificamos el servicio para que permita guardar los saludos : 

package com.hexacta;

import com.hexacta.dao.GreetingDAO;
import com.hexacta.model.Greeting;

import javax.transaction.Transactional;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

@ApplicationScoped
public class GreetingServices {

@Inject
private GreetingDAO dao;

public String greeting(String name) {
return "hola " + name;
}

public String greeting(int id,String name) {
Greeting aGreeting = dao.get(id);
if (aGreeting == null) {
return name;
}
return aGreeting.getValue() + " " + name;
}

@Transactional
public int saveGreeting(String greeting) {
Greeting aGreeting = new Greeting(greeting);
return dao.save(aGreeting);
}
}

Y por último vamos a modificar los servicios REST : 

package com.hexacta;

import org.jboss.resteasy.annotations.jaxrs.PathParam;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

private GreetingServices service;

@Inject
public GreetingResource(GreetingServices service) {
this.service = service;
}

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello RESTEasy";
}

@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/{name}")
public String hello(@PathParam String name) {
return this.service.greeting(name);
}

@POST
@Path("/save/{greeting}")
public int saveGreeting(@PathParam String greeting) {
return this.service.saveGreeting(greeting);
}

@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/{id}/{name}")
public String hello(@PathParam int id,@PathParam String name) {
return this.service.greeting(id, name);
}


}

Y tengo que configurar h2 que es la base que estamos usando, en el application.properties : 

# datasource configuration
quarkus.datasource.db-kind = h2
quarkus.datasource.username = sa
quarkus.datasource.password = a
quarkus.datasource.jdbc.url = jdbc:h2:~/quarkus.db

quarkus.hibernate-orm.database.generation=update

Y listo, podemos guardar diferentes saludos y usarlos. 

Dejo el link del repo : 

https://github.com/emanuelpeg/quarkusExample/