2010-08-22 9 views
5

Ho un'entità che contiene altre due entità con relazione @ManyToOne.Hibernate e NonUniqueObjectException

@Entity 
public class A extends Serializable{ 

    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Long id; 

    @ManyToOne 
    @Cascade(CascadeType.SAVE_UPDATE) 
    private B b; 

    @ManyToOne 
    @Cascade(CascadeType.SAVE_UPDATE) 
    private C c; 

} 

se provo a salvare un Un'istanza che hanno "B_ID" e "C_ID" di un altro record ottengo l'eccezione:

org.hibernate.NonUniqueObjectException: un oggetto diverso con lo stesso valore identificativo è stato già associato alla sessione

Ad esempio:

A table 
| ID | B_ID | C_ID | 
| 1 |  1 | null | // this works 
| 2 | null |  1 | // this works 
| 3 |  1 |  x | // this throws the exception 
| 4 |  x |  1 | // this throws the exception 

x=any value of existent B/C_ID 

B_ID e C_ID non sono univoci nel mio modello e (B_ID + C_ID) non è un vincolo univoco !!

Cosa posso fare?

Grazie in anticipo.

risposta

15

Hibernate non si lamenta dell'unicità del database, ma lamenta che l'attuale Session contenga già un oggetto con lo stesso ID di un nuovo oggetto che si sta tentando di salvare. Non consentirà questo - Hibernate ha un severo requisito che un determinato ID non possa essere rappresentato da due oggetti diversi nell'ambito di una singola sessione.

Ad un certo punto, la tua applicazione ha salvato un'entità con lo stesso ID e quell'oggetto è già "registrato" con la sessione. In questo caso specifico è difficile capire quale ID si stia lamentando, poiché il testo dell'eccezione non è chiaro. Provare a rimuovere temporaneamente le direttive a cascata e vedere se succede ancora, provare a restringere.

Se necessario, è possibile forzare la sessione per "dimenticare" su eventuali oggetti esistenti per un dato ID (usando Session.evict() nell'API Hibernate, o EntityManager.detach() nelle API JPA 2.0), ma non è una soluzione molto elegante.

Per ripetere: questa eccezione non ha nulla a che fare con i vincoli del database, si tratta di Hibernate che protegge la coerenza del suo stato interno in memoria.

+0

Grazie, le uniche cose che carico da db sono B e C, e le uso in un oggetto. Ma B e C hanno CascadeType.SAVE_UPDATE, quindi non vengono salvati di nuovo, ma solo aggiornamento ... spero ... – blow

+0

Anche i problemi si presentano all'inizio, quando la sessione è nuova. – blow

+0

rimuovere le direttive a cascata funziona bene, ma ... PERCHE '??? Senza "Cascade.SAVE_UPDATE" l'ibernazione dovrebbe provare a ri-salvare "A" e "B" che sono già presenti in db e quindi lanciare un'eccezione, ma invece funziona ... perché? – blow

Problemi correlati