Usando Hibernate 5, Spring 4
Considere los códigos a continuación y el mapeo entre dos entidades:
clase de usuario
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user") private TruckOwner truckOwner;// getter setters debajo
Clase TruckOwner
@OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) private User user;// getter setter debajo
Cuando mi código intenta actualizar los valores dentro de la clase de user como el siguiente código: clase UserServiceImpl
@Override @Transactional(propagation = Propagation.REQUIRED, readOnly = false) public void resetPassword(Long userId,String newPassword) { User user = userDAO.findById(userId); user.setPassword(newPassword); System.out.println(user.getTruckOwner().getTruckOwnerId()); userDAO.merge(user); } Al llamar a userDAO.merge(user); Aparece el siguiente error: la entidad no transitoria tiene una identificación nula: com.mymodel.TruckOwner
Estoy enfrentando este tipo de problema en muchos lugares de mi proyecto, ayúdenme con una solución adecuada a este problema y ¿por qué la clase TruckOwner tiene todo nulo establecido por hibernación?
El modo entusiasta no es una solución si está creando una aplicación de producción. El problema es que su sesión ya está cerrada cuando intenta obtener TruckOwner. Intente propagar la sesión a todos los métodos resetPassword .
Primero, ¡no deberías usar merge aquí! Casi nunca debes usar merge.
Merge debe usarse cuando tiene una entidad no administrada (serializado o cargado por un contexto de persistencia anterior) y desea fusionarlo en el contexto de persistencia actual, para convertirlo en una entidad administrada. Su entidad ya está administrada porque se cargó un contexto de persistencia con su DAO dentro de una transacción administrada por contenedor. Esto significa que no tiene que hacer ni siquiera llamar a guardar, cualquier cambio en una entidad administrada se detectará y persistirá cuando se confirme la transacción.
En la superficie, JPA parece fácil, porque gran parte de la complejidad no es visible en la superficie, Dios sabe que me golpeé la cabeza contra la pared cuando comencé con TopLink hace 7 años, pero después de leer sobre los ciclos de vida de los objetos y la administración de aplicaciones versus contenedores contexto de persistencia, cometí muchos más errores y fue mucho más fácil descifrar los mensajes de error.
Deberíamos conocer la implementación del método de userdao merge , pero supongo que se llama el método de merge de la interfaz de Session de hibernación. En cualquier caso, el objeto no transitorio es el objeto TruckOwner ; hibernat no recuperará el objeto cuando llame a System.out.println(user.getTruckOwner().getTruckOwnerId()); además, en ese momento está fuera de la sesión de hibernación y si llama a cualquier otro captador de truckOwner excepto getTruckOwnerId(), debería obtener la org.hibernate.LazyInitializationException (o similar ... no recuerdo correctamente)
Supongo que tienes 2 opciones:
userDAO.findById(userId); debe fetch el objeto truckOwner dentro de la sesión de hibernación llamando a cualquier otro método dentro de userDAO.findById(userId); implementación y dentro de la sesión de hibernaciónespero que sea util
Ángel