2012-01-05 8 views
6

Dada una proyección sencilla como la siguiente, NHibernate depositará el plan de consulta y no actualizar el valor de la variable cuando la consulta es el mismo:LINQ proyección se almacena en caché incorrectamente en NHibernate 3.2

int argValue = 1; 
    var result1 = database.Users.Select(x => new {x.Name, BadArg = argValue}).First(); 

    argValue = 2; 
    var result2 = database.Users.Select(x => new {x.Name, BadArg = argValue}).First(); 

esperado

valor RESULT1 sería Name = "Bob" y BadArg = 1

valor result2 sería Name = "Bob" y BadArg = 2

valor real resultado1

sería Name = "Bob" y BadArg = 1

valor result2 sería Name = "Bob" y BadArg = 1

Obviamente, esto puede causar un montón de comportamiento loco si no lo estás esperando. He visto un couple bug reports similar a este en el seguimiento de fallas de NHibernate, pero no ha habido ninguna acción desde mayo pasado. Entonces, o nadie está usando Linq para Nhibernate mucho o hay alguna solución alternativa que no conozco.

Antes de indagar en el origen de NHibernate, ¿hay alguna manera de deshabilitar el almacenamiento en caché del plan de consulta para evitar este comportamiento o alguna otra solución o alguien ha aplicado el parche desde el enlace anterior?

Nota

El ejemplo está destinado a mantener la cuestión simple, en realidad tengo una proyección complicado que quiero seguir como un IQueryable, prematuramente la conversión a un IEnumerable no va a funcionar.

actualización no funciona en github maestro para Nhibernate 3.2.1

+0

He estado investigando esto por curiosidad, y parece que el problema no es el caché de NHibernate propiamente dicho, sino el caché del árbol de expresiones Linq.El problema es que el árbol de expresiones se simplifica y la referencia de variables se reduce a una expresión constante, después de lo cual se construye la clave de caché, pero en ese momento no se puede decir la diferencia entre una variable scope ref y una constante. : -/ – Rytmis

+0

He estado teniendo este problema también, y es una pérdida de tiempo. Cada pocos meses vuelve a salir, y lo he olvidado, solo para redescubrirlo nuevamente. En mi caso, no estoy proyectando objetos anónimos, sino para valorar objetos de mi propia creación. –

Respuesta

0

Si se quiere evitar el almacenamiento en caché por completo, trate de cambiar su código para esto:

int argValue = 1; 
var result1 = database.Users.AsEnumerable().Select(x => new {x.Name, BadArg = argValue}).First(); 

argValue = 2; 
var result2 = database.Users.AsEnumerable().Select(x => new {x.Name, BadArg = argValue}).First(); 

Lo que pasa es que en lugar de utilizar el método NHLinq Select, terminará utilizando el método System.Linq Select, que previene eficazmente que NHibernate guarde en caché la proyección. Por supuesto, la desventaja es que hará la proyección en la memoria, por lo que terminará seleccionando todos los campos de la tabla de usuarios en lugar de solo los que desea.

+0

Soy consciente de que funcionará, pero en cierto modo frustra el propósito. Mi ejemplo fue simple para la pregunta, pero en realidad quiero mantenerlo como IQueryable. –

0

Así es como para desactivar el caché de primer nivel: http://darioquintana.com.ar/blogging/2007/10/08/statelesssession-nhibernate-without-first-level-cache/

Creo que no se puede desactivar el caché de segundo nivel, pero creo que no tiene que para este problema.

(Esencialmente es lo que necesita para crear y destruir sesiones para cada consulta.)

Si encuentra que el problema sigue siendo persistente sin embargo, usted tiene que hacer lo que sugirió Rytmis.

+0

¡Buena sugerencia! :-) – Rytmis

+0

Crear una sesión diferente solo para ejecutar una consulta parece un poco pesado y podría tener malas consecuencias con los objetos de otra sesión. –

+0

Depende de lo que esté proyectando: si su proyección solo contiene valores escalares, no debería ser un problema. Pero tienes razón, no se siente bien. – Rytmis

Cuestiones relacionadas