Spurgo sessione Hibernate:Dove e quando usarlo, e perché?
-
09-06-2019 - |
Domanda
Una delle cose che mi confonde completamente è l'uso di session.Flush
,insieme a session.Commit
, E session.Close
.
A volte session.Close
funziona, ad esempio, applica tutte le modifiche di cui ho bisogno.So che devo utilizzare commit quando ho una transazione o un'unità di lavoro con diverse creazioni/aggiornamenti/eliminazioni, in modo da poter scegliere di eseguire il rollback se si verifica un errore.
Ma a volte rimango davvero ostacolato dalla logica che sta dietro session.Flush
.Ho visto esempi in cui hai a session.SaveOrUpdate()
seguito da un flush, ma quando rimuovo Flush funziona comunque bene.A volte mi imbatto in errori nell'istruzione Flush che dicono che la sessione è scaduta e rimuovendola mi sono assicurato di non incorrere in 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.
Soluzione
Brevemente:
- Usa sempre le transazioni
- Non utilizzare
Close()
, avvolgi invece le tue chiamate in unISession
all'interno di unusing
dichiarazione o gestisci il ciclo di vita della tua sessione da qualche altra parte.
Di tanto in tanto il
ISession
eseguirà le istruzioni SQL necessarie per sincronizzare lo stato della connessione ADO.NET con lo stato degli oggetti contenuti in memoria.Questo processo, flush, si verifica per impostazione predefinita nei seguenti punti
- da alcune invocazioni di
Find()
OEnumerable()
- da
NHibernate.ITransaction.Commit()
- da
ISession.Flush()
Le istruzioni SQL vengono emesse nel seguente ordine
- tutti gli inserimenti di entità, nello stesso ordine in cui sono stati salvati gli oggetti corrispondenti
ISession.Save()
- tutti gli aggiornamenti dell'entità
- tutte le eliminazioni della raccolta
- tutte le eliminazioni, gli aggiornamenti e gli inserimenti degli elementi della raccolta
- tutti gli inserimenti della collezione
- tutte le eliminazioni di entità, nello stesso ordine in cui sono stati eliminati gli oggetti corrispondenti
ISession.Delete()
(Un'eccezione è rappresentata dal fatto che gli oggetti che utilizzano la generazione di ID nativi vengono inseriti quando vengono salvati.)
Tranne quando esplicitamente
Flush()
, non ci sono assolutamente garanzie su quando la Session esegue le chiamate ADO.NET, solo l'ordine in cui vengono eseguite.Tuttavia, NHibernate garantisce che il fileISession.Find(..)
i metodi non restituiranno mai dati non aggiornati;né restituiranno i dati errati.È possibile modificare il comportamento predefinito in modo che lo svuotamento avvenga meno frequentemente.IL
FlushMode
La classe definisce tre diverse modalità:scarica solo al momento del commit (e solo quando NHibernateITransaction
viene utilizzata l'API), svuota automaticamente utilizzando la routine spiegata o non scarica mai a meno cheFlush()
viene chiamato esplicitamente.L'ultima modalità è utile per unità di lavoro di lunga durata, in cui unISession
rimane aperto e disconnesso per molto tempo.
...
Fare riferimento anche a questa sezione:
La conclusione di una sessione prevede quattro fasi distinte:
- svuotare la sessione
- commettere la transazione
- chiudere la sessione
- gestire le eccezioni
Svuotare la sessione
Se ti capita di utilizzare il
ITransaction
API, non devi preoccuparti di questo passaggio.Verrà eseguito implicitamente al momento del commit della transazione.Altrimenti dovresti chiamareISession.Flush()
per garantire che tutte le modifiche siano sincronizzate con il database.Commiting della transazione del database
Se stai utilizzando l'API NHibernate ITransaction, apparirà così:
tx.Commit(); // flush the session and commit the transaction
Se gestisci tu stesso le transazioni ADO.NET, dovresti farlo manualmente
Commit()
la transazione ADO.NET.sess.Flush(); currentTransaction.Commit();
Se decidi di non confermare le modifiche:
tx.Rollback(); // rollback the transaction
O:
currentTransaction.Rollback();
Se esegui il rollback della transazione dovresti chiudere immediatamente ed eliminare la sessione corrente per garantire che lo stato interno di NHibernate sia coerente.
Chiusura della sessione
Una chiamata a
ISession.Close()
segna la fine di una sessione.L'implicazione principale 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 esso, quindi puoi chiuderlo manualmente o restituirlo al pool.AltrimentiClose()
lo restituisce alla piscina.
Altri suggerimenti
A partire da Hibernate 2.0, le transazioni sono necessarie per le operazioni del DB.quindi, il ITransaction.Commit()
la chiamata gestirà qualsiasi svuotamento necessario.Se per qualche motivo non utilizzi le transazioni NHibernate, non verrà effettuato lo svuotamento automatico della sessione.
Di tanto in tanto la sessione eseguirà le istruzioni SQL necessarie per sincronizzare lo stato della connessione ADO.NET con lo stato degli oggetti contenuti in memoria.
E usalo sempre
using (var transaction = session.BeginTransaction())
{
transaction.Commit();
}
dopo che le modifiche sono state confermate, queste modifiche vengono salvate nel database, utilizziamo Transaction.Commit();
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 di questo, puoi vedere una sezione di codice in cui imposto l'inserimento dell'identità, salvo l'entità, quindi svuoto, quindi disattivo l'inserimento dell'identità.Senza questo svuotamento sembrava che si stesse attivando e disattivando l'inserimento dell'identità e quindi salvando l'entità.
L'uso di Flush() mi ha dato maggiore controllo su ciò che stava succedendo.
Ecco un altro esempio:
Invio del messaggio NServiceBus all'interno di TransactionScope
Non capisco appieno il motivo per cui su questo, ma Flush() ha impedito che si verificasse il mio errore.