Spring: buen uso de entidades administradas/proxies con ORM


Actualmente estoy pensando en cómo manejo mis objetos de dominio junto con hibernación considerando lo siguiente:

  • Mi objeto modelo está anotado directamente con anotación JPA, sin capa de entidad.
  • En algunas operaciones pesadas de la base de datos, no me importa ajustar mi código para aprovechar al máximo los proxies, incluso si podemos considerarlo como una fuga de enmascaramiento de abstracción/implementación. Por supuesto que prefiero cuando puedo hacer lo contrario.
  • Porque no tengo una capa de entidad, no tengo una capa DAO, el administrador de la entidad se considera a sí mismo como una capa DAO (relacionado: encontré JPA, o similar, no fomente el patrón DAO)

Sin embargo, estaba pensando en mejorar lo que estoy haciendo para reducir un poco la complejidad, o al menos, reubicar esa complejidad en un lugar que encaje mejor, como el servicio relacionado de la entidad. Y quizás más abstracto el hecho de que estoy usando un ORM.

Aquí hay un servicio CRUD genérico del que hereda todo mi servicio empresarial.Este código es para mostrarle cómo se hacen las cosas actualmente (anotación, eliminar registros para mayor claridad):

public void create(T entity) {
    this.entityManager.persist(entity);
}
@Transactional(value = TxType.REQUIRED, rollbackOn=NumeroVersionException.class)
public void update(T entity) throws NumeroVersionException{
    try{
        this.entityManager.merge(entity);
    }catch(OptimisticLockException ole){
        throw new NumeroVersionException("for entity "+entity, ole);
    }
}

public T read(int id) {
    return this.entityManager.find(entityClass, id);
}
public void delete(int id) {
    T entity = this.entityManager.getReference(entityClass, id);
    this.entityManager.remove(entity);
    // edit : removed null test thanks to @JBNizet
}

El problema con este tipo de implementación es que si quiero crear un objeto, entonces uso las ventajas de los proxies, básicamente tengo que crearlo y luego recuperarlo. Por supuesto, es posible que la consulta no llegue a la base de datos, sino solo a la memoria caché de Hibernat (aunque no estoy seguro). Pero eso significa que todavía no tengo que olvidar recuperar el proxy.

Esto significa que filtre el hecho de que soy nosotrosing un ORM y proxies detrás de escena.

Así que estaba pensando en cambiar mi interfaz a algo como:

public T read(int id);
public T update(T t)throws NumeroVersionException;
public T create(T object);
public void delete(int id);
List<T> list();

Lo que significa que una vez que pase un objeto a esta capa, tendré que usar el valor devuelto. E implementa actualizaciones específicamente como:

public T update(T t){
    if(!(t instanceof [Proxy class goes there])){
        //+ check if it is a detached proxy
        entityManager.merge(t);
    }  
}

Dado que merge llega a la base de datos cada vez que se llama, para alguna operación que involucre solo algunas entidades de 10, esto puede ser molesto, no lo llamaría en un método de actualización con un proxy.

Por supuesto que espero tener algunos casos extremosdonde necesitaré el EntityManager para vaciar las cosas y así sucesivamente. Pero creo que esto reduciría significativamente la complejidad actual de mi código y aislaría mejor las preocupaciones.

Lo que intento en resumen es reubicar el código ORM dentro del servicio para poder ocultar el hecho de que estoy usando un ORM y proxies y usar la interfaz como si estuviera usando cualquier otra implementación sin perder los beneficios de utilizando un ORM.

La pregunta es así:

  1. ¿Es ese nuevo diseño una buena idea?¿Le gusta esta idea?
  2. ¿Me perdí algo sobre cómo manejar esto correctamente?

Nota: aunque estoy hablando de rendimiento, mi preocupación también es sobre el aislamiento de preocupaciones, la capacidad de mantenimiento y la facilidad de uso para los desarrolladores que no están familiarizados con los ORM y Java con los que trabajo.



------------Respuesta------------

Gracias a @JBNizet, veo algo más claro:

  • Debería usar el valor devuelto por el método merge().
  • Un mLa entidad administrada no siempre es un proxy.
  • No tengo que abstraer el hecho de que uso entidades administradas, esto conducirá a un código complejo e ineficiente
  • Elegí JPA, no lo cambiaré, lo cual es cierto a menos que reescriba el modelo completo para representar algo basado en una base de datos no relacional.

Así que simplemente cambiaré mi método de actualización del código original y me quedaré con el resto.

Etiquetas: proxy-classes jpa spring hibernate orm

Artículos relacionados:

ios: incrustación de anuncios en una vista uitable cada "x" células

redes: ¿por qué 802.1Q no encapsula el marco original?