tutorial net framework example español asp c# .net nhibernate

c# - net - nhibernate vs entity framework



NHibernate Session.Flush() Envío de consultas de actualización cuando no se ha producido ninguna actualización (3)

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 a Session.Flush() al final de HttpRequest , y recibo una HibernateAdoException . NHibernate está pasando una instrucción de actualización a la base de datos y está causando una violación de clave externa. Si no ejecuto el flush , la solicitud se completa sin problemas. El problema aquí es que necesito el lavado en el lugar en caso de que haya un cambio que ocurra dentro de otras sesiones, ya que este código se reutiliza en otras áreas. ¿Hay alguna otra configuración que pueda estar perdiendo?

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 = ?]

Ningún parámetro se muestra como pasado.


He visto esto una vez cuando uno de mis modelos no estaba correlacionado correctamente (no usaba los tipos que aceptan nulos). ¿Puedes pegar tu modelo y mapeo?


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

Convirtiéndolos en access = "field" + agregando un campo en la clase se corrigió el problema. Aunque es bastante difícil rastrearlos.


Siempre tenga cuidado con los campos NULLable cada vez que trabaje 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 generalmente será que NHibernate intentará actualizar el registro en DB, aunque no haya cambiado ningún campo desde que leyó la entidad desde la base de datos.

La siguiente secuencia explica por qué sucede esto:

  1. NHibernate recupera los datos de la entidad sin formato de DB 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 nulo
    • las propiedades de los tipos de punto entero y flotante se establecerán en 0
    • las propiedades del tipo booleano se establecerán en falso
    • 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 del campo original que leyó desde DB, y como el campo contiene NULL pero la propiedad contiene un valor no nulo, NHibernate considera que la propiedad está sucia y obliga a una actualización de la enidad

Esto no solo perjudica el rendimiento (obtienes un viaje de ida y vuelta adicional a la base de datos y una actualización adicional cada vez que recuperas la entidad), sino que también puede causar problemas para solucionar los errores con las columnas de 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, el SqlClient de ADO.NET 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 sencilla es hacer que la propiedad de clase use el tipo Nullable, en este caso, "DateTime?". Alternativamente, podría implementar un mapeador de tipos personalizado implementando IUserType con su método Equals comparando correctamente DbNull.Value con cualquier valor predeterminado de su tipo de valor. En nuestro caso, Equals necesitaría devolver true al comparar 1/1/0001 con DbNull.Value. Implementar un IUserType completamente funcional no es realmente tan difícil, pero sí requiere el conocimiento de NHibernate trivia, así que prepárate para hacer una búsqueda sustancial de Google si decides ir por ese camino.