NHibernate ISession Flush: dónde y cuándo usarlo, y por qué?

Una de las cosas que me confunde por completo es el uso de session.Flush , junto con session.Commit y session.Close .

A veces session.Close funciona, por ejemplo, compromete todos los cambios que necesito. Sé que necesito utilizar 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 realmente me frustra la lógica detrás de la session.Flush . session.Flush . He visto ejemplos en los que tienes una session.SaveOrUpdate() seguido de un color, pero cuando elimino Flush, funciona bien de todos modos. A veces me encuentro con errores en la statement Flush diciendo que la sesión ha excedido el tiempo de espera, y eliminarla me aseguró de que no me encontré con ese error.

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

Brevemente:

  1. Siempre use transacciones
  2. No use Close() , en lugar de eso, ISession sus llamadas a una ISession dentro de una statement de using o administre el ciclo de vida de su ISesión en otro lugar .

De la documentación :

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

  • de algunas invocaciones de Find() o Enumerable()
  • 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, los objetos correspondientes se guardaron 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, los objetos correspondientes se eliminaron usando ISession.Delete()

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

Excepto cuando explicity 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(..) nunca devolverán datos obsoletos; ni devolverán los datos incorrectos.

Es posible cambiar el comportamiento predeterminado para que el enjuague ocurra con menos frecuencia. La clase FlushMode define tres modos diferentes: solo descarga a la hora de confirmación (y solo cuando se usa NHibernate ITransaction API), enjuague automáticamente usando la rutina explicada, o nunca enjuague a menos que se llame Flush() explícitamente. El último modo es útil para unidades de trabajo de larga ejecución, donde una ISession se mantiene abierta y desconectada por un largo tiempo.

También consulte esta sección :

Terminar una sesión implica cuatro fases distintas:

  • enjuagar la sesión
  • comprometer la transacción
  • cerrar la sesión
  • manejar excepciones

Enjuagar la sesión

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

Commitir la transacción de la base de datos

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

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

Si administra las transacciones ADO.NET usted mismo, debe Commit() 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 inmediatamente y descartar la sesión actual para asegurarse de que el estado interno de NHibernate sea coherente.

Cerrando la ISession

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

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

Si proporcionó su propia conexión, Close() devuelve una referencia a ella, por lo que puede cerrarla manualmente o devolverla al grupo. De lo contrario, Close() devuelve al grupo.

A partir de NHibernate 2.0, se requieren transacciones para operaciones DB. Por lo tanto, la llamada ITransaction.Commit() manejará cualquier descarga necesaria. Si por algún motivo no está utilizando las transacciones de NHibernate, no habrá un vaciado automático de la sesión.

Ocasionalmente, ISession ejecutará las sentencias 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(); } 

después de que se hayan confirmado los cambios que esto cambia para guardarlos en la base de datos, usamos transaction.Commit ();

Aquí hay dos ejemplos de mi código donde fallaría sin session.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 establezco el inserto de identidad, guardo la entidad y luego lave, luego configure el inserto de identidad. Sin esta descarga, parecía estar configurando la inserción de identidad y luego guardando la entidad.

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

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.