openxava
/ documentación /
Lección 16: Sincronizar propiedades persistentes y calculadas
Curso:
1.
Primeros pasos |
2.
Modelo básico del dominio (1) |
3.
Modelo básico del dominio (2) |
4.
Refinar la interfaz de usuario |
5.
Desarrollo ágil |
6.
Herencia de superclases mapeadas |
7.
Herencia de entidades |
8.
Herencia de vistas |
9.
Propiedades Java |
10.
Propiedades calculadas |
11.
@DefaultValueCalculator en colecciones |
12.
@Calculation y totales de colección |
13.
@DefaultValueCalculator desde archivo |
14.
Evolución del esquema manual |
15. Cálculo del
valor por defecto multiusuario |
16. Sincronizar propiedades
persistentes y calculadas |
17.
Lógica desde la base de datos |
18.
Validación avanzada |
19.
Refinar el comportamiento predefinido |
20.
Comportamiento y lógica de negocio |
21.
Referencias y colecciones |
A.
Arquitectura y filosofía |
B.
Java Persistence API |
C.
Anotaciones |
D.
Pruebas automáticas
En la lección anterior aprendimos cómo definir propiedades por defecto
para el desarrollo en ambientes multiusuario, utilizando
retrollamadas
JPA. Veremos ahora cómo sincronizar tanto propiedades calculadas
como persistentes.
Si no te gustan los videos sigue
las instrucciones a continuación.
Sincronizar
propiedades persistentes y calculadas
Como ya hemos aprendido, las propiedades calculadas no permiten filtrar ni
ordenar en la lista, por lo que preferimos propiedades persistentes con
@Calculation.
Sin embargo, las propiedades
@Calculation sólo sirven para
cálculos aritméticos simples. Cuando necesitas bucles, condiciones, leer
de la base de datos, conectar a servicios externos o cualquier lógica
compleja,
@Calculation no es suficiente. Para estos casos
necesitas escribir la lógica con Java, en el getter. Pero, ¿cómo podemos
hacer esto y al mismo tiempo mantener la ordenación y el filtrado en la
lista? Fácil, puedes usar dos propiedades, una calculada y otra
persistente, y mantenerlas sincronizadas usando los métodos de
retrollamada de JPA. Vamos a aprender como hacerlo en esta sección.
Añadamos un nueva propiedad a la
entidad Pedido llamada diasEntregaEstimados:
@Depends("fecha")
public int getDiasEntregaEstimados() {
if (getFecha().getDayOfYear() < 15) {
return 20 - getFecha().getDayOfYear();
}
if (getFecha().getDayOfWeek() == DayOfWeek.SUNDAY) return 2;
if (getFecha().getDayOfWeek() == DayOfWeek.SATURDAY) return 3;
return 1;
}
Esto es una propiedad calculada
pura, un getter con lógica Java. Calcula los día estimados de entrega
usando fecha como fuente. Este caso no puede solucionarse con @Calculation
que solo soporta operaciones aritméticas básicas.
También hemos de añadir diasEntregaEstimados
a la declaración de la @View por defecto en el código de Pedido:
@View(extendsView="super.DEFAULT",
members=
"diasEntregaEstimados," + // AÑADE ESTA LÍNEA
"factura { factura }"
)
...
public class Pedido extends DocumentoComercial {
El resultado es este:
El valor se recalcula cada vez
que la fecha cambia en la interfaz de usuario gracias a el @Depends("fecha")
en diasEntregaEstimados. Todo esto está muy bien, pero cuando
vas al modo lista no puedes ordenar ni filtrar por días estimados de
entrega. Para solucionar este problema añadimos una segunda propiedad,
esta vez persistente. Agrega el siguiente código a tu entidad Pedido:
@Column(columnDefinition="INTEGER DEFAULT 1")
int diasEntrega;
Ten en cuenta que hemos usado @Column(columnDefinition="INTEGER
DEFAULT 1"), con este truco cuando OpenXava crea la columna usa
"INTEGER DEFAULT 1" como definición de columna, por lo que la nueva
columna tiene 1 como valor predeterminado en lugar de nulo, y nosotros
evitamos un feo error con nuestra propiedad int. Sí, en muchos casos @Column(columnDefinition=)
es una alternativa para hacer una ACTUALIZACIÓN sobre la tabla (como
hicimos en la lección "Evolución manual del esquema"), aunque tiene el
problema de que depende de la base de datos. De todos modos, esta
disertación de columnDefinition es tangencial a nuestro problema
de sincronización calculada/persistente, @Column no es del todo
necesaria, solo es conveniente para nuestra propiedad int. Esta nueva
propiedad diasEntrega contendrá el mismo valor que diasEntregaEstimados,
pero diasEntrega será persistente con su columna correspondiente
en la base de datos. El truco está en mantener sincronizada la propiedad
diasEntrega. Usaremos los métodos de retrollamadas JPA en la
clase de Pedido. Basta con asignar el valor de díasEntregaEstimados
a diasEntrega cada vez que se crea un nuevo pedido (@PrePersist)
o se actualiza (@PreUpdate). Agreguemos un nuevo método recalcularDiasEntrega()
a la entidad de pedido anotada con @PrePersist y @PreUpdate,
por lo tanto:
@PrePersist @PreUpdate
private void recalcularDiasEntrega() {
setDiasEntrega(getDiasEntregaEstimados());
}
Básicamente, el método recalcularDiasEntrega()
se llama cada vez que se registra una entidad de Pedido en la
base de datos por primera vez y cuando se actualiza el pedido. Puedes
probar el módulo Pedido con este código, y verás como cuando se
crea o modifica un pedido, la columna de la base de datos para diasEntrega
se actualiza correctamente después de guardar, lista para ser utilizada
en procesamiento masivo y disponible para ordenar y filtrar lista.