2009-06-15 11 views
0

Quelle est la meilleure pratique d'Hibernate lorsque vous devez annuler des relations de clés étrangères, mais ne voulez pas rejeter la transaction (par exemple, continuer à enregistrer d'autres données)? Si je viens de passer l'exception sauvegarder la pile ou ne pas faire cette annulation, alors j'atteindrai une erreur quand j'essaye d'enregistrer les autres données (Null ou l'objet Passient passé à persister) comme les BookingLines sont déjà persisté.Annulation des relations de clé étrangère avec Hibernate

Je manipulons actuellement la rollback en ajoutant les nouvelles entités à une carte, puis les retirer des listes d'entités en cas d'échec comme suit:

/* Method that will try to create an invoice but won't roll back the transaction if 
* a currency rate can't be found. 
*/ 
public void createInvoiceFromBooking(Booking booking) { 

    Invoice invoice = new Invoice(); 

    //Map to hold entities that I want to roll back 
    Map<BookingLine, InvoiceLine> addedLines = new HashMap<BookingLine, InvoiceLine>(); 

    try { 
    for(BookingLine bookingLine : booking.getBookingLines()) { 
     InvoiceLIne invoiceLIne = new InvoiceLIne(); 

     //do stuff that can throw exception 
     applyCurrencyRate(invoiceLine); 

     bookingLine.getInvoiceLines().add(invoiceLine); 
     invoice.getInvoiceLines().add(invoiceLine); 

     //add to the "rollback" map 
     addedLines.put(bookingLine, invoiceLine); 
    } 
    } catch (Exception e) { 
    //remove the InvoiceLines from the related entities 
    for(BookingLine bookingLine : addedLines.keySet()) { 
     bookingLine.getInvoiceLines().remove(addedLines.get(bookingLine)); 
    } 
    } 

Cela fonctionne, mais se sent mal. Y a-t-il un meilleur moyen?

Un bookingLine.clear() n'est pas bon car il peut avoir d'autres liens InvoiceLine déjà enregistrés.

Merci.

+1

Ce que vous faites est appelé «transaction de compensation». Dans votre cas, vous souhaitez rester avec la transaction en cours tout en annulant des parties de celui-ci. Fondamentalement, vous agissez comme si le commit/rollback n'est pas disponible mais vous restez dans les limites d'une seule transaction. Cela ne me poserait aucun problème étant donné que vous ne pouvez pas utiliser commit/rollback pour accomplir la même chose. – topchef

Répondre

2

Les contraintes sur la base de données sont créées à partir de la structure de vos objets. En d'autres termes, si vous violez les contraintes, il y a un problème avec vos relations d'objet. Par exemple, vous avez A pointant vers B mais aucun point B vers A, ou vous avez spécifié une relation pour ne pas autoriser les valeurs nulles et il y a une valeur nulle.

Pour cette raison, vous devriez envisager de ne pas vous fier aux contraintes pour maintenir la cohérence de votre modèle d'objet. Ce serait mieux, et moins sujet aux erreurs si en fait vous vous êtes assuré que votre modèle d'objet était cohérent en vérifiant le modèle d'objet, plutôt que de se fier à la base de données pour le faire.

En outre, il n'est jamais une bonne idée que l'exception ne soit pas un cas exceptionnel. Les exceptions sont là pour gérer les erreurs, elles devraient être un chemin d'exploitation "normal". Pour cette raison, en ce qui concerne votre exemple, je vous suggère plutôt de vérifier la devise, et si ce n'est pas le cas, de ne pas ajouter vos données dans le magasin persistant.

+0

+1 Je fais souvent cela aussi, mais la raison de la question était de déterminer si quelqu'un avait une bonne approche pour revenir en arrière. Vous ne pouvez pas toujours prévoir tous les résultats et il est souvent agréable de compter sur la gestion des exceptions. – Damo

Questions connexes