NHibernate ISession Flush: ¿Dónde y cuándo usarlo y por qué?

187

Una de las cosas que me confunden completamente es el uso de session.Flush, junto con session.Commity session.Close.

A veces session.Closefunciona, por ejemplo, confirma todos los cambios que necesito. Sé que necesito usar commit cuando tengo una transacción, o una unidad de trabajo con varias creaciones / actualizaciones / eliminaciones, para poder elegir deshacer si ocurre un error.

Pero a veces la lógica detrás me obstaculiza session.Flush. He visto ejemplos en los que tienes un session.SaveOrUpdate()rubor seguido, pero cuando elimino el rubor funciona bien de todos modos. A veces me encuentro con errores en la declaración de Flush que dice que la sesión se agotó, y al eliminarla me aseguré de no encontrarme con ese error.

¿Alguien tiene una buena directriz sobre dónde o cuándo usar una descarga? He revisado la documentación de NHibernate para esto, pero todavía no puedo encontrar una respuesta directa.

Jon Limjap
fuente

Respuestas:

236

Brevemente:

  1. Siempre use transacciones
  2. No use Close(), en su lugar, envuelva sus llamadas ISessiondentro de una usingdeclaración o administre el ciclo de vida de su ISession en otro lugar .

De la documentación :

De vez en cuando ISession, ejecutará las instrucciones SQL necesarias para sincronizar el estado de la conexión ADO.NET con el estado de los objetos almacenados en la memoria. Este proceso, flush, ocurre por defecto en los siguientes puntos

  • de algunas invocaciones de Find()oEnumerable()
  • de NHibernate.ITransaction.Commit()
  • de ISession.Flush()

Las sentencias SQL se emiten en el siguiente orden

  1. todas las inserciones de entidades, en el mismo orden en que se guardaron los objetos correspondientes usando ISession.Save()
  2. todas las actualizaciones de la entidad
  3. todas las eliminaciones de colecciones
  4. todas las eliminaciones, actualizaciones e inserciones de elementos de colección
  5. todas las inserciones de colección
  6. todas las eliminaciones de entidades, en el mismo orden en que se eliminaron los objetos correspondientes usando ISession.Delete()

(Una excepción es que los objetos que utilizan la generación de ID nativa se insertan cuando se guardan).

Excepto cuando explícitamente Flush(), no hay absolutamente ninguna garantía sobre cuándo la Sesión ejecuta las llamadas ADO.NET, solo el orden en que se ejecutan . Sin embargo, NHibernate garantiza que los ISession.Find(..)métodos nunca devolverán datos obsoletos; ni devolverán los datos incorrectos.

Es posible cambiar el comportamiento predeterminado para que el vaciado ocurra con menos frecuencia. La FlushModeclase define tres modos diferentes: solo enjuagar en el momento de la confirmación (y solo cuando ITransactionse usa la API de NHibernate ), enjuagar automáticamente usando la rutina explicada o nunca enjuagar a menos que Flush()se llame explícitamente. El último modo es útil para unidades de trabajo de larga duración, donde ISessionse mantiene abierto y desconectado durante mucho tiempo.

...

Consulte también esta sección :

Terminar una sesión implica cuatro fases distintas:

  • lavar la sesión
  • cometer la transacción
  • cerrar la sesión
  • manejar excepciones

Vaciar la sesión

Si está utilizando la ITransactionAPI, no necesita preocuparse por este paso. Se realizará implícitamente cuando se confirme la transacción. De lo contrario, debe llamar ISession.Flush()para asegurarse de que todos los cambios estén sincronizados con la base de datos.

Confirmar la transacción de la base de datos

Si está utilizando la API de NHibernate ITransaction, esto se ve así:

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

Si está gestionando transacciones ADO.NET usted mismo, debe realizar manualmente Commit()la transacción ADO.NET.

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

Si decide no comprometer sus cambios:

tx.Rollback();  // rollback the transaction

o:

currentTransaction.Rollback();

Si revierte la transacción, debe cerrar y descartar inmediatamente la sesión actual para asegurarse de que el estado interno de NHibernate sea coherente.

Cerrando la sesión

Una llamada a ISession.Close()marca el final de una sesión. La implicación principal de Close () es que la sesión abandonará la conexión ADO.NET.

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

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

Si proporcionó su propia conexión, le Close()devuelve una referencia, para que pueda cerrarla manualmente o devolverla al grupo. De Close()lo contrario, lo devuelve al grupo.

Matt Hinze
fuente
2
para mí, esta línea fue clave: "La principal implicación de Close () es que la sesión abandonará la conexión ADO.NET". si no llama a ISession.Close (), sus conexiones se llenarán hasta que obtenga tiempos de espera de db. : o
dave thieben
Usualmente: sesión abierta session.BeginTransaction () trabajo ... session.Transaction.Commit () session.BeginTransaction () trabajo ... session.Transaction.Commit () session.BeginTransaction () trabajo .. session.Transaction.Commit () disponer sesión.
Agile Jedi
Escritura brillante y +1 y etc., sin embargo, creo que podría ser necesaria una edición porque dice en la parte superior "Nunca use cerrar" y luego "Si revierte la transacción, debe cerrar inmediatamente y descartar la sesión actual"
SpaceBison
¿Se puede cambiar el orden de las instrucciones SQL? Quiero decir que necesito realizar una actualización sobre un objeto de entidad y luego insertarlo porque tengo una restricción en la tabla correspondiente.
bob_saginowski
14

A partir de NHibernate 2.0, se requieren transacciones para las operaciones de base de datos. Por lo tanto, la ITransaction.Commit()llamada manejará cualquier descarga necesaria. Si por alguna razón no está utilizando las transacciones de NHibernate, no habrá enjuague automático de la sesión.

Sean Carpenter
fuente
1

De vez en cuando, el ISession ejecutará las instrucciones SQL necesarias para sincronizar el estado de la conexión ADO.NET con el estado de los objetos almacenados en la memoria.

Y siempre usa

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

una vez que se confirman los cambios, estos cambios se guardan en la base de datos, utilizamos la transacción.Commit ();

gaders
fuente
0

Aquí hay dos ejemplos de mi código donde fallaría sin sesión. Flush ():

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

al final de esto, puede ver una sección de código donde configuro la inserción de identidad, guardo la entidad y luego la descarga, luego apago la inserción de identidad. Sin esta descarga, parecía estar activando y desactivando la inserción de identidad y luego guardando la entidad.

El uso de Flush () me dio más control sobre lo que estaba sucediendo.

Aquí hay otro ejemplo:

Enviar mensaje NServiceBus dentro de TransactionScope

No entiendo completamente por qué en este caso, pero Flush () evitó que ocurriera mi error.

Paul T Davies
fuente