2010-01-14 8 views
13

Je ces entitésMise en veille prolongée - une collection de compensation avec tout delete-orphan puis en y ajoutant les causes ConstraintViolationException

class Foo{ 
    Set<Bar> bars; 
} 

class Bar{ 
    Foo parent; 
    String localIdentifier; 
} 

Avec cette mise en correspondance (désolé, pas d'annotations, je suis vieux jeu):

<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> 

J'ai aussi une contrainte unique sur 2 colonnes: local_identifier et parent_id (pas une contrainte unique sur chacun, mais une seule contrainte unique, contenant à la fois, par exemple, pas sont autorisés 2 lignes avec le même parent et même LocalIdentifier) ​​

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

Et ce code qui les utilise:

//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); 

Maintenant, pour une raison quelconque, Hibernate n'exécute pas les choses dans l'ordre où ils ont été appelés. Il n'exécute pas clear() (supprimer) avant la add() (insert), mais vice-versa, il essaie d'abord d'insérer, d'obtenir un ConstraintViolationException

Je sais que l'ajout d'un peu session.flush() après bars.clear();, pourrait résoudre ce problème, mais dans ce cas , Je n'ai pas accès à la session d'une manière non laide.

Est-ce que le flush est la seule solution? ou existe-t-il une version Hibernate qui respecte l'ordre des actions?

Mise à jour: Par ailleurs, la collection déréférencement entraînera une HibernateException de https://www.hibernate.org/117.html#A3:

Je me HibernateException: Ne pas déréférencer une collection avec cascade = "all-delete -orphan " Ce se produira si vous chargez un objet avec une collection cascade =" all-delete-orphan " , puis supprimez la référence de la collection. Ne pas remplacer cette collection, utilisez clear() de sorte que l'algorithme de suppression orphelin peut détecter votre changement.

+2

Je pense que flushing est la seule option ici – ruchirhhi

+0

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

Répondre

8

Je suppose qu'il n'y a pas d'alternative à la chasse d'eau

De here:

Hibernate viole une contrainte unique!

Hibernate n'est pas tout à fait aussi intelligent avec des contraintes uniques car est avec des clés étrangères. Parfois, vous devrez donner un petit indice.

une violation de contrainte unique pourrait se produire si deux objets sont mis à jour tous les deux étant , on est « Annuler » une valeur et l'autre est « l'obtention » la même valeur. Une solution de contournement consiste à flush() la session manuellement après la mise à jour le premier objet et avant la mise à jour le deuxième.

(Ce genre de problème se produit rarement dans la pratique .)

1

Si vous voulez éviter le rinçage de la session ici, essayez de remplacer toute la liste (new List<Bar>() au lieu de Clear()). Hibernate devrait effectivement supprimer tous les éléments d'un coup avant d'en ajouter de nouveaux. Juste un essai, je ne sais pas si cela fonctionne.

+1

Merci, mais non: https://www.hibernate.org/117.html#A3 Je vais mettre à jour la question –

1

Si vous utilisez Oracle, vous pouvez également utiliser des contraintes de reportables de reporter la vérification des contraintes jusqu'à ce que la transaction est validée. Vous ne savez pas si/comment cela est supporté par d'autres bases de données.