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 { ...@@ -66,7 +66,7 @@ public class Cliente implements Serializable {
List<Tarjeta> tarjetas; List<Tarjeta> tarjetas;
/** Cuentas asociadas al cliente */ /** Cuentas asociadas al cliente */
@OneToMany(mappedBy="titular") @OneToMany(mappedBy="titular", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
List<Cuenta> cuentas; List<Cuenta> cuentas;
public Cliente() { 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; ...@@ -21,6 +21,8 @@ import es.ujaen.dae.ujacoin.servicios.ServicioUjaCoin;
import jakarta.validation.ConstraintViolationException; import jakarta.validation.ConstraintViolationException;
import jakarta.validation.constraints.Positive; import jakarta.validation.constraints.Positive;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
...@@ -207,8 +209,8 @@ public class ControladorREST { ...@@ -207,8 +209,8 @@ public class ControladorREST {
LocalDateTime fechaInicial; LocalDateTime fechaInicial;
LocalDateTime fechaFinal; LocalDateTime fechaFinal;
try { try {
fechaInicial = desdeFecha != null ? LocalDateTime.parse(desdeFecha) : null; fechaInicial = desdeFecha != null ? LocalDateTime.parse(desdeFecha) : LocalDateTime.of(1980, Month.JANUARY, 1, 0, 0);
fechaFinal = hastaFecha != null ? LocalDateTime.parse(hastaFecha) : null; fechaFinal = hastaFecha != null ? LocalDateTime.parse(hastaFecha) : LocalDateTime.of(2100, Month.JANUARY, 1, 0, 0);
} catch (DateTimeParseException e) { } catch (DateTimeParseException e) {
return ResponseEntity.badRequest().build(); return ResponseEntity.badRequest().build();
} }
......
...@@ -20,6 +20,7 @@ import jakarta.validation.constraints.NotNull; ...@@ -20,6 +20,7 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive; import jakarta.validation.constraints.Positive;
import es.ujaen.dae.ujacoin.repositorios.RepositorioClientes; import es.ujaen.dae.ujacoin.repositorios.RepositorioClientes;
import es.ujaen.dae.ujacoin.repositorios.RepositorioCuentas; import es.ujaen.dae.ujacoin.repositorios.RepositorioCuentas;
import es.ujaen.dae.ujacoin.repositorios.RepositorioMovimientos;
import jakarta.validation.constraints.Past; import jakarta.validation.constraints.Past;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
...@@ -47,6 +48,9 @@ public class ServicioUjaCoin { ...@@ -47,6 +48,9 @@ public class ServicioUjaCoin {
RepositorioCuentas repositorioCuentas; RepositorioCuentas repositorioCuentas;
@Autowired @Autowired
RepositorioMovimientos repositorioMovimientos;
@Autowired
CacheManager cacheManager; CacheManager cacheManager;
public ServicioUjaCoin() { public ServicioUjaCoin() {
...@@ -62,13 +66,12 @@ public class ServicioUjaCoin { ...@@ -62,13 +66,12 @@ public class ServicioUjaCoin {
if (test.isPresent()) { if (test.isPresent()) {
throw new ClienteYaRegistrado(); throw new ClienteYaRegistrado();
} }
repositorioClientes.guardar(cliente);
// Crear y registrar cuenta // Crear y registrar cuenta
Cuenta cuenta = crearCuenta(cliente); Cuenta cuenta = new Cuenta(generarNumCuenta(), cliente);
repositorioCuentas.guardar(cuenta); cliente.nuevaCuenta(cuenta);
repositorioClientes.guardar(cliente);
return cuenta; return cuenta;
} }
...@@ -83,8 +86,6 @@ public class ServicioUjaCoin { ...@@ -83,8 +86,6 @@ public class ServicioUjaCoin {
Optional<Cliente> clienteLogin = repositorioClientes.buscar(dni) Optional<Cliente> clienteLogin = repositorioClientes.buscar(dni)
.filter((cliente)->cliente.claveValida(clave)); .filter((cliente)->cliente.claveValida(clave));
// Asegurarnos de que se devuelve el cliente con los datos precargados
clienteLogin.ifPresent(c -> c.verCuentas().size());
return clienteLogin; return clienteLogin;
} }
...@@ -98,8 +99,6 @@ public class ServicioUjaCoin { ...@@ -98,8 +99,6 @@ public class ServicioUjaCoin {
public Optional<Cliente> verCliente(@NotBlank String dni) { public Optional<Cliente> verCliente(@NotBlank String dni) {
Optional<Cliente> clienteLogin = repositorioClientes.buscar(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; return clienteLogin;
} }
...@@ -112,8 +111,9 @@ public class ServicioUjaCoin { ...@@ -112,8 +111,9 @@ public class ServicioUjaCoin {
public Cuenta crearCuenta(@NotBlank String dni) { public Cuenta crearCuenta(@NotBlank String dni) {
Cliente cliente = repositorioClientes.buscar(dni).orElseThrow(ClienteNoRegistrado::new); Cliente cliente = repositorioClientes.buscar(dni).orElseThrow(ClienteNoRegistrado::new);
Cuenta cuenta = crearCuenta(cliente); Cuenta cuenta = new Cuenta(generarNumCuenta(), cliente);
repositorioCuentas.guardar(cuenta); cliente.nuevaCuenta(cuenta);
repositorioClientes.actualizar(cliente);
return cuenta; return cuenta;
} }
...@@ -212,19 +212,21 @@ public class ServicioUjaCoin { ...@@ -212,19 +212,21 @@ public class ServicioUjaCoin {
cuentaDestino.nuevoMovimiento(new TransferenciaRecibida(cuentaOrigen, importe)); cuentaDestino.nuevoMovimiento(new TransferenciaRecibida(cuentaOrigen, importe));
} }
/** /**
* Devolver la lista de movimientos de la cuenta, filtrada por fechas * Devolver la lista de movimientos de la cuenta, filtrada por fechas
* @param numCuenta el número de la cuenta * @param numCuenta el número de la cuenta
* @param fechaHoraDesde la fecha inicial * @param fechaHoraDesde la fecha inicial
* @param fechaHoraHasta la fecha final * @param fechaHoraHasta la fecha final
* @return la lista de los movimientos entre las fechas indicadas * @return la lista de los movimientos entre las fechas indicadas
*/ */
@Transactional public List<Movimiento> listarMovimientosCuentaDesdeHasta(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde, LocalDateTime fechaHoraHasta) {
public List<Movimiento> listarMovimientosCuentaDesdeHasta(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde, @Past LocalDateTime fechaHoraHasta) {
Cuenta cuenta = repositorioCuentas.buscar(numCuenta) Cuenta cuenta = repositorioCuentas.buscar(numCuenta)
.orElseThrow(CuentaNoRegistrada::new); .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 { ...@@ -233,16 +235,19 @@ public class ServicioUjaCoin {
* @param fechaHoraDesde fecha de primer movimiento * @param fechaHoraDesde fecha de primer movimiento
* @return el listado de movimientos * @return el listado de movimientos
*/ */
@Transactional public List<Movimiento> listarMovimientosCuentaDesde(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde) {
public List<Movimiento> listarMovimientosDesde(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde) {
Cuenta cuenta = repositorioCuentas.buscar(numCuenta) Cuenta cuenta = repositorioCuentas.buscar(numCuenta)
.orElseThrow(CuentaNoRegistrada::new); .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 // 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 // Generar número de cuenta de 10 dígitos aleatorio y no usado previamente
String numCuenta; String numCuenta;
long min = 1000000000L; long min = 1000000000L;
...@@ -251,11 +256,6 @@ public class ServicioUjaCoin { ...@@ -251,11 +256,6 @@ public class ServicioUjaCoin {
numCuenta = Long.toString(min + (long) (Math.random() * (max - min))); numCuenta = Long.toString(min + (long) (Math.random() * (max - min)));
} while (repositorioCuentas.buscar(numCuenta).isPresent()); } while (repositorioCuentas.buscar(numCuenta).isPresent());
Cuenta cuenta = new Cuenta(numCuenta, cliente); return numCuenta;
// No es necesario al ser una relación bidireccional gestionada por JPA
// cliente.nuevaCuenta(cuenta);
return cuenta;
} }
} }
...@@ -21,7 +21,6 @@ import org.assertj.core.api.Assertions; ...@@ -21,7 +21,6 @@ import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; 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;
import org.springframework.test.annotation.DirtiesContext.MethodMode; import org.springframework.test.annotation.DirtiesContext.MethodMode;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
...@@ -158,10 +157,10 @@ public class ServicioUjaCoinTest { ...@@ -158,10 +157,10 @@ public class ServicioUjaCoinTest {
// Realizar ingreso y comprobar estado de la cuenta // Realizar ingreso y comprobar estado de la cuenta
servicioUjaCoin.ingreso(cuentas.get(0).getNum(), tarjeta.getNum(), 1000); 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).hasSize(1);
Assertions.assertThat(movimientos.get(0)).isInstanceOf(Ingreso.class); 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 @Test
...@@ -208,13 +207,13 @@ public class ServicioUjaCoinTest { ...@@ -208,13 +207,13 @@ public class ServicioUjaCoinTest {
cuentaDestino = servicioUjaCoin.verCuentas(cliente2.getDni()).get(0); cuentaDestino = servicioUjaCoin.verCuentas(cliente2.getDni()).get(0);
// Listar movimientos de la cuenta origen // 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).hasSize(2);
Assertions.assertThat(movimientos.get(1)).isInstanceOf(TransferenciaEmitida.class); Assertions.assertThat(movimientos.get(1)).isInstanceOf(TransferenciaEmitida.class);
Assertions.assertThat(cuentaOrigen.getSaldo()).isEqualTo(500); Assertions.assertThat(cuentaOrigen.getSaldo()).isEqualTo(500);
// Listar movimientos de la cuenta destino // 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).hasSize(1);
Assertions.assertThat(movimientos.get(0)).isInstanceOf(TransferenciaRecibida.class); Assertions.assertThat(movimientos.get(0)).isInstanceOf(TransferenciaRecibida.class);
Assertions.assertThat(cuentaDestino.getSaldo()).isEqualTo(500); 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