NHibernate ISession Flush: dove e quando usarlo e perché?


187

Una delle cose che mi rende completamente confuso è l'uso session.Flush, in combinazione con session.Commit, e session.Close.

A volte session.Closefunziona, ad esempio, commette tutti i cambiamenti di cui ho bisogno. So di dover utilizzare il commit quando ho una transazione o un'unità di lavoro con diverse crea / aggiornamenti / eliminazioni, in modo da poter scegliere di eseguire il rollback in caso di errore.

Ma a volte sono davvero ostacolato dalla logica che sta dietro session.Flush. Ho visto esempi in cui hai session.SaveOrUpdate()seguito un flush, ma quando rimuovo Flush funziona comunque bene. A volte mi imbatto in errori nell'affermazione Flush dicendo che la sessione è scaduta e la sua rimozione mi ha assicurato che non ho riscontrato quell'errore.

Qualcuno ha una buona linea guida su dove o quando usare un flush? Ho controllato la documentazione di NHibernate per questo, ma non riesco ancora a trovare una risposta semplice.

Risposte:


236

Brevemente:

  1. Usa sempre le transazioni
  2. Non utilizzare Close(), invece avvolgi le tue chiamate ISessionall'interno di usingun'istruzione o gestisci il ciclo di vita di ISession da qualche altra parte .

Dalla documentazione :

Di tanto in tanto ISessioneseguiranno le istruzioni SQL necessarie per sincronizzare lo stato della connessione ADO.NET con lo stato degli oggetti conservati in memoria. Questo processo, flush, si verifica per impostazione predefinita nei seguenti punti

  • da alcune invocazioni di Find()oEnumerable()
  • a partire dal NHibernate.ITransaction.Commit()
  • a partire dal ISession.Flush()

Le istruzioni SQL vengono emesse nel seguente ordine

  1. tutti gli inserimenti di entità, nello stesso ordine in cui sono stati salvati gli oggetti corrispondenti ISession.Save()
  2. tutti gli aggiornamenti delle entità
  3. tutte le eliminazioni di raccolte
  4. tutte le eliminazioni, gli aggiornamenti e gli inserimenti degli elementi di raccolta
  5. tutti gli inserimenti di raccolta
  6. tutte le eliminazioni di entità, nello stesso ordine in cui gli oggetti corrispondenti sono stati eliminati usando ISession.Delete()

(Un'eccezione è che gli oggetti che utilizzano la generazione dell'ID nativo vengono inseriti quando vengono salvati.)

Tranne quando esplicitamente Flush(), non ci sono assolutamente garanzie su quando la Sessione esegue le chiamate ADO.NET, solo l'ordine in cui vengono eseguite . Tuttavia, NHibernate garantisce che i ISession.Find(..)metodi non restituiranno mai dati non aggiornati; né restituiranno i dati errati.

È possibile modificare il comportamento predefinito in modo che lo scarico avvenga meno frequentemente. La FlushModeclasse definisce tre diverse modalità: svuota solo al momento del commit (e solo quando ITransactionviene utilizzata l' API NHibernate ), svuota automaticamente usando la routine spiegata o non svuota mai a meno che non Flush()sia chiamata esplicitamente. L'ultima modalità è utile per le unità di lavoro a esecuzione prolungata, in cui una ISessionviene mantenuta aperta e disconnessa per lungo tempo.

...

Fare riferimento anche a questa sezione :

La conclusione di una sessione prevede quattro fasi distinte:

  • svuota la sessione
  • impegnare la transazione
  • chiudi la sessione
  • gestire le eccezioni

Lavaggio della sessione

Se ti capita di usare l' ITransactionAPI, non devi preoccuparti di questo passaggio. Verrà eseguito in modo implicito quando viene eseguita la transazione. In caso contrario, è necessario chiamare ISession.Flush()per assicurarsi che tutte le modifiche siano sincronizzate con il database.

Commettere la transazione del database

Se stai usando l'API NHibernate ITransaction, questo appare come:

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

Se gestisci tu stesso le transazioni ADO.NET, dovresti eseguire manualmente Commit()la transazione ADO.NET.

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

Se decidi di non eseguire il commit delle modifiche:

tx.Rollback();  // rollback the transaction

o:

currentTransaction.Rollback();

Se si esegue il rollback della transazione, è necessario chiudere immediatamente ed eliminare la sessione corrente per assicurarsi che lo stato interno di NHibernate sia coerente.

Chiusura della sessione

Una chiamata per ISession.Close()segnare la fine di una sessione. La principale implicazione di Close () è che la connessione ADO.NET verrà abbandonata dalla sessione.

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

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

Se hai fornito la tua connessione, Close()restituisce un riferimento ad essa, in modo da poterla chiudere manualmente o restituirla al pool. Altrimenti lo Close()restituisce al pool.


2
per me, questa riga era la chiave: "L'implicazione principale di Close () è che la connessione ADO.NET verrà abbandonata dalla sessione." se non chiami ISession.Close (), le tue connessioni vengono riempite fino a quando non ottieni timeout db. : o
dave thieben,

Di solito: apriamo la sessione session.BeginTransaction () work ... session.Transaction.Commit () session.BeginTransaction () work ... session.Transaction.Commit () session.BeginTransaction () work .. session.Transaction.Commit () smaltire la sessione.
Agile Jedi

Brilliant write-up e +1 ed ecc - tuttavia penso che potrebbe essere necessaria una modifica perché dici all'inizio "Non usare mai vicino" e successivamente "Se esegui il rollback della transazione, dovresti chiudere immediatamente ed eliminare la sessione corrente"
SpaceBison

È possibile modificare l'ordine delle istruzioni SQL? Voglio dire, devo eseguire l'aggiornamento su un oggetto entità e poi inserire perché ho un vincolo nella tabella corrispondente.
bob_saginowski il

14

A partire da NHibernate 2.0, sono necessarie transazioni per le operazioni DB. Pertanto, la ITransaction.Commit()chiamata gestirà qualsiasi svuotamento necessario. Se per qualche motivo non stai utilizzando le transazioni NHibernate, non verrà eseguito lo svuotamento automatico della sessione.


1

Di tanto in tanto ISession eseguirà le istruzioni SQL necessarie per sincronizzare lo stato della connessione ADO.NET con lo stato degli oggetti conservati in memoria.

E usa sempre

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

dopo che le modifiche sono state impegnate rispetto a queste modifiche per salvare nel database, utilizziamo transazione.Commit ();


0

Ecco due esempi del mio codice in cui fallirebbe senza session.Flush ():

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

alla fine, puoi vedere una sezione di codice in cui ho impostato l'inserimento dell'identità, salvare l'entità quindi svuotare, quindi disattivare l'inserimento dell'identità. Senza questo flush sembrava attivare e disattivare l'inserimento dell'identità, quindi salvare l'entità.

L'uso di Flush () mi ha dato un maggiore controllo su ciò che stava succedendo.

Ecco un altro esempio:

Invio del messaggio NServiceBus all'interno di TransactionScope

Non capisco bene perché su questo, ma Flush () ha impedito il mio errore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.