2010-01-14 11 views
13

ho queste entitàHibernate - compensazione una collezione con tutti i-delete-orphan e aggiungendo ad esso provoca ConstraintViolationException

class Foo{ 
    Set<Bar> bars; 
} 

class Bar{ 
    Foo parent; 
    String localIdentifier; 
} 

Con questa mappatura (sorry, no annotazioni, io sono vecchio stile):

<class name="Foo"> 
    ... 
    <set name="bars" cascade="all-delete-orphan" lazy="false" inverse="true"> 
     <key>...</key> 
     <one-to-many class="Bar"/> 
    </set> 
</class> 


<class name="Bar"> 
    ... 
    <property name="localIdentifier" column="local_identifier"/> 
    <many-to-one name="parent" column="parent_id" /> 
</class> 

ho anche di un vincolo univoco 2 colonne: local_identifier e parent_id (non un vincolo univoco su ciascuno, ma un unico vincolo unico contenente sia, ad esempio, non sono permessi 2 righe con lo stesso genitore e stessa localIdentifier) ​​

alter table bar add constraint unique_bar unique (parent_id, local_identifier) 

E questo codice che li utilizza:

//foo is persistent, foo id = 1 
Bars bars = foo.getBars(); 
bars.clear(); // bars contained 1 item [parent_id = 1, local_identifier = "a"] 
Bar newBar = new Bar(); 
newBar.setParent(foo); 
newBar.setLocalIdentifier("a"); 
bars.add(newBar); 

Ora, per qualche ragione, Hibernate non esegue le cose nell'ordine in cui sono stati chiamati. Non esegue il clear() (cancellare) prima della add() (inserto), ma viceversa, si cerca prima di inserire, ottenendo un ConstraintViolationException

So che l'aggiunta di un po 'session.flush() dopo bars.clear();, potrebbe risolvere questo problema, ma in questo caso , Non ho accesso alla sessione in modo non brutto.

Quindi flush è l'unica soluzione? o c'è una versione di Hibernate che rispetta l'ordine delle azioni?

Aggiornamento: A proposito, dereferenziazione la collezione si tradurrà in una HibernateException da https://www.hibernate.org/117.html#A3:

ottengo HibernateException: Non dereference una collezione con cascade = "all-delete -orphan " Questo si verifica se si carica un oggetto con a cascata =" tutto-elimina-orfano " insieme e quindi si rimuove il riferimento alla raccolta. Non sostituire questa raccolta, utilizzare clear() in modo che l'algoritmo di eliminazione orfana possa rilevare la modifica.

+2

Penso che il flushing sia l'unica opzione qui – ruchirhhi

+0

Relative [argomento Hibernate Forum] (https://forum.hibernate.org/viewtopic.php?t=934483). –

risposta

8

Credo che non c'è alternativa al lavaggio

Da here:

Hibernate sta violando un vincolo di unicità!

Hibernate non è proprio come intelligente con vincoli univoci in quanto è con chiavi esterne. A volte il tuo potrebbe dare un piccolo suggerimento.

Una violazione vincolo unico potrebbe verificarsi se due oggetti sono entrambi essendo aggiornato, uno è "Rilascio" un valore e l'altro è "ottenendo" lo stesso valore . Una soluzione alternativa è flush() la sessione manualmente dopo l'aggiornamento del primo oggetto e prima dell'aggiornamento dello secondo.

(Questo tipo di problema si verifica raramente in pratica.)

1

Se si vuole evitare il lavaggio della sessione di qui, provare a sostituire l'intera lista (new List<Bar>() invece di Clear()). Hibernate dovrebbe effettivamente rimuovere tutti gli elementi in un colpo solo prima di aggiungerne uno nuovo. Solo una prova, non so se funziona.

+1

Grazie, ma no: https://www.hibernate.org/117.html#A3 aggiornerò la domanda –

1

Se si utilizza Oracle, si potrebbe anche utilizzare i vincoli differibili di rinviare la verifica dei vincoli fino a quando la transazione è impegnata. Non sono sicuro se/come questo è supportato da altri database.

Problemi correlati