Si tengo una relación con @OneToMany @Cascade (CascadeType.SAVE_UPDATE) de la siguiente manera¿Cómo habilitar Hibernate Interceptor cuando tengo mi Hibernate Transaction administrada por Spring?
public class One {
private Integer id;
private List<Many> manyList = new ArrayList<Many>();
@Id
@GeneratedValue
public Integer getId() {
return this.id;
}
@OneToMany
@JoinColumn(name="ONE_ID", updateable=false, nullable=false)
@Cascade(CascadeType.SAVE_UPDATE)
public List<Many> getManyList() {
return this.manyList;
}
}
Y Muchos clase
public class Many {
private Integer id;
/**
* required no-arg constructor
*/
public Many() {}
public Many(Integer uniqueId) {
this.id = uniqueId
}
/**
* Without @GeneratedValue annotation
* Hibernate will use assigned Strategy
*/
@Id
public Integer getId() {
return this.id;
}
}
si tengo el siguiente escenario
One one = new One();
/**
* generateUniqueId method will Take care of assigning unique id for each Many instance
*/
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
Y llamo
sessionFactory.getCurrentSession().save(one);
Antes de pasar
Según Transitive persistence documentación de referencia de Hibernate, se puede ver
Si un padre se pasa a save(), actualizar() o saveOrUpdate(), todos los niños se pasan a saveOrUpdate()
ok. Ahora vamos a ver lo que Java Persistence con Hibernate libro habla de método saveOrUpdate
Hibernate consulta la tabla de muchos para el identificador dado, y si se encuentra, Hibernate actualiza la fila. Si no se encuentra, , se requiere la inserción de una nueva fila.
que se puede traducir de acuerdo con
INSERT INTO ONE (ID) VALUES (?)
/**
* I have four Many instances added To One instance
* So four select-before-saving
*
* I DO NOT NEED select-before-saving
* Because i know i have a Fresh Transient instance
*/
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
Cualquier solución para evitar select-before-ahorro ??? Sí, puede
- Añadir una columna @Version (No aplica)
- implementar el método isTransient proporcionado por Hibernate interceptor (La opción tengo)
Así como una forma de evitar el comportamiento predeterminado al utilizar este tipo de conexión en cascada, he mejorado mi código asignando un Hibernate Interceptor a una sesión de Hibernate cuya transacción es gestionada por Spring.
Aquí va mi repositorio
Antes (Sin ningún interceptor de Hibernate): Funciona bien!
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.getCurrentSession().save(instance);
}
}
Después (con Hibernate Inteceptor): algo va mal (No se consulta SQL se realiza - Ni INSERTAR Tampoco select-before-AHORRO)
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.openSession(new EmptyInterceptor() {
/**
* To avoid select-before-saving
*/
@Override
public Boolean isTransient(Object o) {
return true;
}
}).save(instance);
}
}
Mi pregunta es: ¿Por qué la primavera no lo hace persistir en mi Entidad y sus relaciones al usar Hibernate Interceptor y ¿qué debo hacer como solución para que funcione bien?
Como dije: * Puede agregar un Interceptor a la SessionFactory *. Sucede si agrego un Interceptor a SessionFactory, obtendré un comportamiento ** global **. Solo quiero agregar un Interceptor a la instancia de la Sesión que se usa con el método add (SomeEntity instance). ¿Alguna solución? –