NHibernate ISession Flush: où et quand l'utiliser, et pourquoi?

187

L’utilisation de session.Flush, en conjonction avec session.Commitet session.Close.

Fonctionne parfois session.Close, par exemple, il valide tous les changements dont j'ai besoin. Je sais que je dois utiliser la validation lorsque j'ai une transaction ou une unité de travail avec plusieurs créations / mises à jour / suppressions, afin de pouvoir choisir de revenir en arrière si une erreur se produit.

Mais parfois, je suis vraiment bloqué par la logique derrière session.Flush. J'ai vu des exemples où vous avez un session.SaveOrUpdate()suivi d'un flush, mais quand je supprime Flush, cela fonctionne bien de toute façon. Parfois, je rencontre des erreurs sur l'instruction Flush en disant que la session a expiré et en la supprimant, je me suis assuré de ne pas rencontrer cette erreur.

Quelqu'un a-t-il une bonne directive sur où et quand utiliser une chasse d'eau? J'ai consulté la documentation NHibernate pour cela, mais je ne trouve toujours pas de réponse simple.

Jon Limjap
la source

Réponses:

236

Brièvement:

  1. Utilisez toujours les transactions
  2. N'utilisez pas Close(), enveloppez plutôt vos appels sur une déclaration ISessionintérieure usingou gérez le cycle de vie de votre ISession ailleurs .

De la documentation :

De temps en temps, le ISessionexécutera les instructions SQL nécessaires pour synchroniser l'état de la connexion ADO.NET avec l'état des objets conservés en mémoire. Ce processus, flush, se produit par défaut aux points suivants

  • à partir de certaines invocations de Find()ouEnumerable()
  • de NHibernate.ITransaction.Commit()
  • de ISession.Flush()

Les instructions SQL sont émises dans l'ordre suivant

  1. toutes les insertions d'entités, dans le même ordre, les objets correspondants ont été enregistrés en utilisant ISession.Save()
  2. toutes les mises à jour d'entité
  3. toutes les suppressions de collections
  4. toutes les suppressions, mises à jour et insertions d'éléments de collection
  5. toutes les insertions de collection
  6. toutes les suppressions d'entités, dans le même ordre que les objets correspondants ont été supprimés en utilisant ISession.Delete()

(Une exception est que les objets utilisant la génération d'ID natif sont insérés lorsqu'ils sont enregistrés.)

Sauf lorsque vous explicitez Flush(), il n'y a absolument aucune garantie sur le moment où la session exécute les appels ADO.NET, seulement l'ordre dans lequel ils sont exécutés . Cependant, NHibernate garantit que les ISession.Find(..)méthodes ne renverront jamais de données périmées; ils ne renverront pas non plus les mauvaises données.

Il est possible de modifier le comportement par défaut afin que le vidage se produise moins fréquemment. La FlushModeclasse définit trois modes différents: vider uniquement au moment de la validation (et uniquement lorsque l' ITransactionAPI NHibernate est utilisée), vider automatiquement à l'aide de la routine expliquée, ou ne jamais vider à moins d' Flush()être appelé explicitement. Le dernier mode est utile pour les unités de travail de longue durée, où un ISessionest maintenu ouvert et déconnecté pendant une longue période.

...

Reportez-vous également à cette section :

La fin d'une session comporte quatre phases distinctes:

  • vider la session
  • valider la transaction
  • fermer la session
  • gérer les exceptions

Rinçage de la session

Si vous utilisez l' ITransactionAPI, vous n'avez pas à vous soucier de cette étape. Elle sera exécutée implicitement lorsque la transaction est validée. Sinon, vous devez appeler ISession.Flush()pour vous assurer que toutes les modifications sont synchronisées avec la base de données.

Validation de la transaction de base de données

Si vous utilisez l'API NHibernate ITransaction, cela ressemble à:

tx.Commit(); // flush the session and commit the transaction

Si vous gérez vous-même des transactions ADO.NET, vous devez manuellement Commit()la transaction ADO.NET.

sess.Flush();
currentTransaction.Commit();

Si vous décidez de ne pas valider vos modifications:

tx.Rollback();  // rollback the transaction

ou:

currentTransaction.Rollback();

Si vous annulez la transaction, vous devez immédiatement fermer et ignorer la session en cours pour vous assurer que l'état interne de NHibernate est cohérent.

Clôture de la session

Un appel à ISession.Close()marque la fin d'une session. L'implication principale de Close () est que la connexion ADO.NET sera abandonnée par la session.

tx.Commit();
sess.Close();

sess.Flush();
currentTransaction.Commit();
sess.Close();

Si vous avez fourni votre propre connexion, Close()renvoie une référence à celle-ci, afin que vous puissiez la fermer manuellement ou la renvoyer au pool. Sinon, le Close()renvoie à la piscine.

Matt Hinze
la source
2
pour moi, cette ligne était la clé: "L'implication principale de Close () est que la connexion ADO.NET sera abandonnée par la session." si vous n'appelez pas ISession.Close (), vos connexions sont remplies jusqu'à ce que vous obteniez des délais d'expiration de la base de données. : o
dave thieben
Habituellement, nous: ouvrons session session.BeginTransaction () travail ... session.Transaction.Commit () session.BeginTransaction () travail ... session.Transaction.Commit () session.BeginTransaction () travail .. session.Transaction.Commit () supprimer la session.
Agile Jedi
Écriture brillante et +1 et etc. - cependant, je pense qu'une modification pourrait être nécessaire car vous dites en haut "Ne jamais utiliser de fermeture", puis plus tard "Si vous annulez la transaction, vous devez immédiatement fermer et supprimer la session en cours"
SpaceBison
L'ordre des instructions SQL peut-il être modifié. Je veux dire que je dois effectuer une mise à jour sur un objet entité et que l'insérer parce que j'ai une contrainte dans le tableau correspondant.
bob_saginowski
14

À partir de NHibernate 2.0, les transactions sont requises pour les opérations DB. Par conséquent, l' ITransaction.Commit()appel gérera tout rinçage nécessaire. Si pour une raison quelconque vous n'utilisez pas de transactions NHibernate, il n'y aura pas de vidage automatique de la session.

Sean Carpenter
la source
1

De temps en temps, l'ISession exécutera les instructions SQL nécessaires pour synchroniser l'état de la connexion ADO.NET avec l'état des objets conservés en mémoire.

Et toujours utiliser

 using (var transaction = session.BeginTransaction())
 {
     transaction.Commit();
 }

une fois les modifications validées, ces modifications sont enregistrées dans la base de données, nous utilisons transaction.Commit ();

ganders
la source
0

Voici deux exemples de mon code où il échouerait sans session.Flush ():

http://www.lucidcoding.blogspot.co.uk/2012/05/changing-type-of-entity-persistence.html

à la fin de cela, vous pouvez voir une section de code dans laquelle je active l'insertion d'identité, enregistre l'entité puis vide, puis désactive l'insertion d'identité. Sans ce rinçage, il semblait activer et désactiver l'insertion d'identité, puis enregistrer l'entité.

L'utilisation de Flush () m'a donné plus de contrôle sur ce qui se passait.

Voici un autre exemple:

Envoi d'un message NServiceBus dans TransactionScope

Je ne comprends pas parfaitement pourquoi sur celui-ci, mais Flush () a empêché mon erreur de se produire.

Paul T Davies
la source