Se ho un rapporto con @OneToMany @Cascade (CascadeType.SAVE_UPDATE) come segueCome abilitare Hibernate Interceptor quando ho la mia Hibernate Transaction gestita da 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;
}
}
e molti classe
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;
}
}
se ho il seguente scenario
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()));
E chiamo
sessionFactory.getCurrentSession().save(one);
Prima di andare in
Secondo Transitive persistence documentazione di riferimento Hibernate, è possibile vedere
Se un genitore viene passato per salvare(), update() o saveOrUpdate(), tutti i bambini sono passati a saveOrUpdate()
ok. Ora vediamo cosa Java Persistence con Hibernate libro parla di metodo saveOrUpdate
Hibernate interroga la tabella di molti, in data id e se si trova, Hibernate aggiorna la riga. Se non viene trovato, l'inserimento di una nuova riga è obbligatorio e completato.
che può essere tradotto in base alle
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 (?, ?)
Qualsiasi soluzione per evitare select-before-risparmio ??? Sì, è possibile
- Aggiungere una colonna @Version (non applicato)
- implementare il metodo isTransient forniti da Hibernate intercettore (L'opzione che ho)
Così come un modo per evitare il comportamento predefinito di select-before-saving quando si utilizza questo tipo di collegamento in cascata, ho migliorato il mio codice assegnando un Hibernate Interceptor a una Hibernate Session cui transazione è gestita da Spring.
Qui va il mio repository
Prima (Senza alcun Hibernate Interceptor): Funziona bene!
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.getCurrentSession().save(instance);
}
}
Dopo (con Hibernate Inteceptor): qualcosa va storto (No query SQL viene eseguita - Né INSERT Nor select-PRIMA DI RISPARMIO)
@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);
}
}
La mia domanda è: perché Primavera non lo fa persiste la mia Entità e le sue relazioni quando uso Hibernate Interceptor e cosa dovrei fare come soluzione per lavorare bene ???
Come detto: * È possibile aggiungere un intercettore a SessionFactory *. Succede se aggiungo un Interceptor a SessionFactory, otterrò un comportamento ** globale **. Voglio solo aggiungere un Interceptor all'istanza Session che viene utilizzata dal metodo add (SomeEntity instance). Qualche soluzione? –