Sesión NHibernate.Flush () Enviando Consultas De Actualización Cuando No Se Ha Producido Ninguna Actualización


Tengo una sesión de NHibernate. En esta sesión, estoy realizando exactamente 1 operación, que es ejecutar este código para obtener una lista:

public IList<Customer> GetCustomerByFirstName(string customerFirstName)
{
return _session.CreateCriteria(typeof(Customer))
    .Add(new NHibernate.Expression.EqExpression("FirstName", customerFirstName))
    .List<Customer>();
}

Estoy llamando Session.Flush() al final del HttpRequest, y obtengo un HibernateAdoException. NHibernate está pasando una instrucción update a la base de datos y causando una violación de clave foránea. Si no corro el flush, la solicitud se completa sin ningún problema. El problema aquí es que necesito el color en su lugar en caso de que haya un cambio que ocurra dentro de otras sesiones, ya que este código es reutilizado en otras áreas. ¿Hay otra configuración que podría faltar?


Aquí está el código de la excepción:

[SQL: UPDATE CUSTOMER SET first_name = ?, last_name = ?, strategy_code_1 = ?, strategy_code_2 = ?, strategy_code_3 = ?, dts_import = ?, account_cycle_code = ?, bucket = ?, collector_code = ?, days_delinquent_count = ?, external_status_code = ?, principal_balance_amount = ?, total_min_pay_due = ?, current_balance = ?, amount_delinquent = ?, current_min_pay_due = ?, bucket_1 = ?, bucket_2 = ?, bucket_3 = ?, bucket_4 = ?, bucket_5 = ?, bucket_6 = ?, bucket_7 = ? WHERE customer_account_id = ?]

No se muestran parámetros como pasados.

Author: NullUserException, 2008-08-29

3 answers

He visto esto una vez antes cuando uno de mis modelos no estaba mapeado correctamente (no estaba usando tipos nullables correctamente). ¿Puede pegar su modelo y mapeo?

 14
Author: Ryan Duffield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-29 18:35:23

Siempre tenga cuidado con los campos nullables cada vez que trate con NHibernate. Si su campo es NULLable en DB, asegúrese de que la clase. NET correspondiente también use el tipo Nullable. De lo contrario, todo tipo de cosas extrañas sucederán. El síntoma suele ser que NHibernate intentará actualizar el registro en la base de datos, aunque no haya cambiado ningún campo desde que leyó la entidad de la base de datos.

La siguiente secuencia explica por qué esto sucede:

  1. NHibernate recupera raw datos de la entidad de la base de datos utilizando ADO.NET
  2. NHibernate construye la entidad y establece sus propiedades
  3. Si el campo DB contiene NULL, la propiedad se establecerá en el valor predeterminado para su tipo:
    • las propiedades de los tipos de referencia se establecerán en null
    • las propiedades de los tipos entero y coma flotante se establecerán en 0
    • las propiedades del tipo booleano se establecerán en false
    • las propiedades del tipo DateTime se establecerán en DateTime.MinValue
    • etc.
  4. Ahora, cuando se confirma la transacción, NHibernate compara el valor de la propiedad con el valor de campo original que lee la forma DB, y dado que el campo contenía NULL pero la propiedad contiene un valor no nulo, NHibernate considera la propiedad sucia, y fuerza una actualización de la enity.

No solo esto perjudica el rendimiento (obtienes un viaje de ida y vuelta extra a la base de datos y una actualización adicional cada vez que recuperas la entidad), sino que también puede causar errores difíciles de solucionar con las columnas DateTime. De hecho, cuando la propiedad DateTime se inicializa a su valor predeterminado, se establece en 1/1/0001. Cuando este valor se guarda en DB, ADO.NET SqlClient no puede convertirlo a un valor SqlDateTime válido ya que el SqlDateTime más pequeño posible es 1/1/1753!!!

La solución más fácil es hacer que la propiedad class use Nullable type, en este caso "DateTime?". Alternativamente, puede implementar un mapeador de tipos personalizado implementando IUserType con su Igual método comparando correctamente DBNull.Valor con cualquier valor predeterminado de su tipo de valor. En nuestro caso Equals tendría que devolver true al comparar 1/1/0001 con DBNull.Valor. Implementar un IUserType completamente funcional no es realmente tan difícil, pero requiere conocimiento de NHibernate trivia, así que prepárese para hacer un googleo sustancial si elige ir por ese camino.

 45
Author: zvolkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-27 16:46:59

También experimenté este problema en NH 2.0.1 al tratar de ocultar los extremos inversos de muchas a muchas bolsas usando access="noop" (pista: esto no funciona).

Convertirlos a access="field" + agregar un campo en la clase solucionó el problema. Aunque es bastante difícil localizarlos.

 0
Author: Richard Dingwall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-18 04:20:40