Commit 1ed77d32 by Antonio Rueda

Mejora de la eficiencia de las búsquedas de movimientos.

Carga y operaciones en cascada en relación cliente-cuentas
parent e8feaa98
......@@ -66,7 +66,7 @@ public class Cliente implements Serializable {
List<Tarjeta> tarjetas;
/** Cuentas asociadas al cliente */
@OneToMany(mappedBy="titular")
@OneToMany(mappedBy="titular", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
List<Cuenta> cuentas;
public Cliente() {
......
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package es.ujaen.dae.ujacoin.repositorios;
import es.ujaen.dae.ujacoin.entidades.Cuenta;
import es.ujaen.dae.ujacoin.entidades.movimientos.Movimiento;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Repository
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class RepositorioMovimientos {
@PersistenceContext
EntityManager em;
public List<Movimiento> buscarDesdeFechaHora(Cuenta c, LocalDateTime fechaHora) {
return em.createQuery("select m from Cuenta c join c.movimientos m where c = ?1 and m.fechaHora >= ?2")
.setParameter(1, c)
.setParameter(2, fechaHora)
.getResultList();
}
public List<Movimiento> buscarDesdeHastaFechaHora(Cuenta c, LocalDateTime fechaHoraDesde, LocalDateTime fechaHoraHasta) {
return em.createQuery("select m from Cuenta c join c.movimientos m where c.num = ?1 and m.fechaHora between ?2 and ?3")
.setParameter(1, c.getNum())
.setParameter(2, fechaHoraDesde)
.setParameter(3, fechaHoraHasta)
.getResultList();
}
}
......@@ -21,6 +21,8 @@ import es.ujaen.dae.ujacoin.servicios.ServicioUjaCoin;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.constraints.Positive;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.Optional;
......@@ -207,8 +209,8 @@ public class ControladorREST {
LocalDateTime fechaInicial;
LocalDateTime fechaFinal;
try {
fechaInicial = desdeFecha != null ? LocalDateTime.parse(desdeFecha) : null;
fechaFinal = hastaFecha != null ? LocalDateTime.parse(hastaFecha) : null;
fechaInicial = desdeFecha != null ? LocalDateTime.parse(desdeFecha) : LocalDateTime.of(1980, Month.JANUARY, 1, 0, 0);
fechaFinal = hastaFecha != null ? LocalDateTime.parse(hastaFecha) : LocalDateTime.of(2100, Month.JANUARY, 1, 0, 0);
} catch (DateTimeParseException e) {
return ResponseEntity.badRequest().build();
}
......
......@@ -20,6 +20,7 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import es.ujaen.dae.ujacoin.repositorios.RepositorioClientes;
import es.ujaen.dae.ujacoin.repositorios.RepositorioCuentas;
import es.ujaen.dae.ujacoin.repositorios.RepositorioMovimientos;
import jakarta.validation.constraints.Past;
import java.time.LocalDateTime;
import java.util.List;
......@@ -47,6 +48,9 @@ public class ServicioUjaCoin {
RepositorioCuentas repositorioCuentas;
@Autowired
RepositorioMovimientos repositorioMovimientos;
@Autowired
CacheManager cacheManager;
public ServicioUjaCoin() {
......@@ -62,13 +66,12 @@ public class ServicioUjaCoin {
if (test.isPresent()) {
throw new ClienteYaRegistrado();
}
repositorioClientes.guardar(cliente);
// Crear y registrar cuenta
Cuenta cuenta = crearCuenta(cliente);
repositorioCuentas.guardar(cuenta);
Cuenta cuenta = new Cuenta(generarNumCuenta(), cliente);
cliente.nuevaCuenta(cuenta);
repositorioClientes.guardar(cliente);
return cuenta;
}
......@@ -83,8 +86,6 @@ public class ServicioUjaCoin {
Optional<Cliente> clienteLogin = repositorioClientes.buscar(dni)
.filter((cliente)->cliente.claveValida(clave));
// Asegurarnos de que se devuelve el cliente con los datos precargados
clienteLogin.ifPresent(c -> c.verCuentas().size());
return clienteLogin;
}
......@@ -98,8 +99,6 @@ public class ServicioUjaCoin {
public Optional<Cliente> verCliente(@NotBlank String dni) {
Optional<Cliente> clienteLogin = repositorioClientes.buscar(dni);
// Asegurarnos de que se devuelve el cliente con los datos precargados
clienteLogin.ifPresent(c -> c.verCuentas().size());
return clienteLogin;
}
......@@ -112,8 +111,9 @@ public class ServicioUjaCoin {
public Cuenta crearCuenta(@NotBlank String dni) {
Cliente cliente = repositorioClientes.buscar(dni).orElseThrow(ClienteNoRegistrado::new);
Cuenta cuenta = crearCuenta(cliente);
repositorioCuentas.guardar(cuenta);
Cuenta cuenta = new Cuenta(generarNumCuenta(), cliente);
cliente.nuevaCuenta(cuenta);
repositorioClientes.actualizar(cliente);
return cuenta;
}
......@@ -212,19 +212,21 @@ public class ServicioUjaCoin {
cuentaDestino.nuevoMovimiento(new TransferenciaRecibida(cuentaOrigen, importe));
}
/**
/**
* Devolver la lista de movimientos de la cuenta, filtrada por fechas
* @param numCuenta el número de la cuenta
* @param fechaHoraDesde la fecha inicial
* @param fechaHoraHasta la fecha final
* @return la lista de los movimientos entre las fechas indicadas
*/
@Transactional
public List<Movimiento> listarMovimientosCuentaDesdeHasta(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde, @Past LocalDateTime fechaHoraHasta) {
public List<Movimiento> listarMovimientosCuentaDesdeHasta(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde, LocalDateTime fechaHoraHasta) {
Cuenta cuenta = repositorioCuentas.buscar(numCuenta)
.orElseThrow(CuentaNoRegistrada::new);
return cuenta.listarMovimientosDesdeHasta(fechaHoraDesde, fechaHoraHasta);
// Ineficiente
// return cuenta.listarMovimientosDesdeHasta(fechaHoraDesde, fechaHoraHasta);
return repositorioMovimientos.buscarDesdeHastaFechaHora(cuenta, fechaHoraDesde, fechaHoraHasta);
}
/**
......@@ -233,16 +235,19 @@ public class ServicioUjaCoin {
* @param fechaHoraDesde fecha de primer movimiento
* @return el listado de movimientos
*/
@Transactional
public List<Movimiento> listarMovimientosDesde(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde) {
public List<Movimiento> listarMovimientosCuentaDesde(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde) {
Cuenta cuenta = repositorioCuentas.buscar(numCuenta)
.orElseThrow(CuentaNoRegistrada::new);
return cuenta.listarMovimientosDesde(fechaHoraDesde);
// Ineficiente
// return cuenta.listarMovimientosDesde(fechaHoraDesde);
return repositorioMovimientos.buscarDesdeFechaHora(cuenta, fechaHoraDesde);
}
// Crear una cuenta para el cliente indicado con un número no asignado
private Cuenta crearCuenta(Cliente cliente) {
private String generarNumCuenta() {
// Generar número de cuenta de 10 dígitos aleatorio y no usado previamente
String numCuenta;
long min = 1000000000L;
......@@ -251,11 +256,6 @@ public class ServicioUjaCoin {
numCuenta = Long.toString(min + (long) (Math.random() * (max - min)));
} while (repositorioCuentas.buscar(numCuenta).isPresent());
Cuenta cuenta = new Cuenta(numCuenta, cliente);
// No es necesario al ser una relación bidireccional gestionada por JPA
// cliente.nuevaCuenta(cuenta);
return cuenta;
return numCuenta;
}
}
......@@ -21,7 +21,6 @@ import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.MethodMode;
import org.springframework.test.context.ActiveProfiles;
......@@ -158,10 +157,10 @@ public class ServicioUjaCoinTest {
// Realizar ingreso y comprobar estado de la cuenta
servicioUjaCoin.ingreso(cuentas.get(0).getNum(), tarjeta.getNum(), 1000);
List<Movimiento> movimientos = servicioUjaCoin.listarMovimientosDesde(cuentas.get(0).getNum(), LocalDateTime.MIN);
List<Movimiento> movimientos = servicioUjaCoin.listarMovimientosCuentaDesdeHasta(cuentas.get(0).getNum(), LocalDateTime.now().minusDays(1), LocalDateTime.now().plusHours(1));
Assertions.assertThat(movimientos).hasSize(1);
Assertions.assertThat(movimientos.get(0)).isInstanceOf(Ingreso.class);
Assertions.assertThat(movimientos.get(0).getImporte()).isEqualTo(1000);
Assertions.assertThat(movimientos.get(0).getImporte()).isEqualTo(1000);
}
@Test
......@@ -208,13 +207,13 @@ public class ServicioUjaCoinTest {
cuentaDestino = servicioUjaCoin.verCuentas(cliente2.getDni()).get(0);
// Listar movimientos de la cuenta origen
List<Movimiento> movimientos = servicioUjaCoin.listarMovimientosDesde(cuentaOrigen.getNum(), LocalDateTime.MIN);
List<Movimiento> movimientos = servicioUjaCoin.listarMovimientosCuentaDesde(cuentaOrigen.getNum(), LocalDateTime.now().minusDays(1));
Assertions.assertThat(movimientos).hasSize(2);
Assertions.assertThat(movimientos.get(1)).isInstanceOf(TransferenciaEmitida.class);
Assertions.assertThat(cuentaOrigen.getSaldo()).isEqualTo(500);
// Listar movimientos de la cuenta destino
movimientos = servicioUjaCoin.listarMovimientosDesde(cuentaDestino.getNum(), LocalDateTime.MIN);
movimientos = servicioUjaCoin.listarMovimientosCuentaDesde(cuentaDestino.getNum(), LocalDateTime.now().minusDays(1));
Assertions.assertThat(movimientos).hasSize(1);
Assertions.assertThat(movimientos.get(0)).isInstanceOf(TransferenciaRecibida.class);
Assertions.assertThat(cuentaDestino.getSaldo()).isEqualTo(500);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment