JPA EntityManager persistono () che fa apparire l'oggetto staccato anche se è stato lanciato un errore
-
12-11-2019 - |
Domanda
Ciao ho un semplice dao con la funzione seguente.
public element createElement(Element e){
em.persist(e);
em.flush();
return e;
}
La tabella delle entità ha un vincolo unico sulla coppia (tipo, valore) e ho un test di seguito:
public void testCreateElement() throws DataAccessException {
// Start with empty Element table
Element e = new Element();
e.setType(myType.OTHER);
e.setValue("1");
dao.createElement(e);
e = new Element();
e.setType(MyType.OTHER);
e.setValue("1");
try{
// this should violate unique constraint of database.
dao.createElement(e);
} catch (Exception ex) {
System.out.println(ex);
}
e.setValue("2");
try{
// I expect this to work as there is no element with these values.
dao.createElement(e);
} catch (Exception ex) {
System.out.println(ex);
}
}
Il mio primo errore catturato avviene come mi aspetto dal momento che so che sto violando il vincolo, il secondo tentativo/cattura non dovrebbe lanciare un errore per quanto mi riguarda, ma lo fa, quello che ottengo è questo:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mypackage.Element
Quindi sembra chiamare persistere () su "e" anche se non è stato persistito ha fatto sì che Hibernate pensasse che sia un'entità distaccata.
Questo è fastidioso perché queste funzioni vengono utilizzate da un front -end JSF che sta affrontando l'eccezione di vincolo, ma trattenendo deliberatamente l'oggetto in modo che l'utente possa cambiare uno dei campi e riprovare e provare l'errore di entità distaccata .
Questo comportamento è un bug in letargo perché non penso che dovrebbe farlo davvero? C'è un modo per aggirare questo a livello di DAO in modo che persiste non trattare il mio oggetto come distaccato se non è effettivamente persistito?
Saluti,
Glen x
Soluzione
Un'eccezione lanciata da Hibernate non è recuperabile. L'unica cosa che dovresti mai fare quando si verifica tale eccezione è il rollback e chiudere la sessione. Lo stato della sessione (e delle sue entità) dopo tale eccezione è instabile.
Se vuoi conservare una copia dell'elemento intatta, usa merge()
piuttosto che persist()
, o clonare l'elemento prima di persistere.
Si noti che è prevista l'eccezione, poiché quando Hibernate persiste e scarica l'entità, inizia generando un ID e assegnando l'ID all'entità, quindi inserisce la riga, il che provoca l'eccezione. Quindi, dopo l'eccezione, l'entità ha un ID assegnato ed è quindi considerata un'entità distaccata da Hibernate. Potresti provare a ripristinare l'ID su NULL e vedere se funziona, ma preferirei clonare l'entità prima o uso unione.