2011-02-10 19 views
11

tengo una tabla llamada "test", que sólo tiene 1 columna, "NullableInt" (anulable tipo int)LINQ devuelve 0 resultados si se utiliza resultados anulables int variables, precisos si el uso de "nulo"

Los registros son : 1, 2, nula

int? nullableInt = null; 
var t = db.tests.Where(x => x.NullableInt == null).ToList(); // returns 1 record 
var t2 = db.tests.Where(x => x.NullableInt == nullableInt).ToList(); // returns 0 records 

Por alguna razón, t2 devuelve 0 registros, incluso aunque se trata de utilizar "nullableInt" variable, que tiene un valor nulo, al igual que t, lo que se compara contra la "nula"

¡Cualquier ayuda sería muy apreciada!

Respuesta

2

las consultas se podrían construir de esta manera:

var q = db.tests; 
if(nullableInt.HasValue) 
{ 
    q = q.Where(x => x.NullableInt == nullableInt.Value); 
} 
else 
{ 
    q = q.Where(x => x.NullableInt == null); 
} 
var t2 = q.ToList(); 
+0

+1 Apesta, pero es la única forma en que parece = ( – Francisco

+0

Consulte mi respuesta a continuación, esto se soluciona en EF6 y puede optar por una corrección en EF5. –

6

Sí, es un error en LINQ-to-SQL/Entity Framework. IS NULL Las consultas solo se generarán si codifica nulo en la consulta, en lugar de una variable que actualmente es nula.

La segunda consulta generará

SELECT ....... 
WHERE NullableInt == @someParam 
WHERE @someParam is null. 

Cuando la primera generará el apropiado IS NULL en la cláusula WHERE.

Si está utilizando LINQ-to-SQL, puede registrar sus consultas en Console.Out para verlo usted mismo, y si está utilizando EF, entonces ToTraceString() debería mostrarle la misma información (o SQL) perfilador servidor)

+2

En realidad, no creo que sea un error porque en la segunda expresión 'nullableInt' no es' null' incluso asigna su valor con 'nullableInt = null' (ya que es una estructura, cuyo valor no puede ser nulo) . Por lo tanto, el marco lo trata como otras estructuras (como un int). –

+2

@Danny, eso es dividir los pelos. El error podría estar en la especificación, incluso si el código hace exactamente lo que la especificación dice que debería hacer. En otras palabras, el error aquí podría no ser que el código haga algo mal, pero que alguien no consideró este escenario. –

+1

Separación de pelos de hecho. No hay ninguna razón justificable por la cual el analizador de EF deba generar la segunda consulta para que sea algo más que IS NULL. Y esto se ha registrado como un error con MS (con un recuento de votos muy elevado) aunque no tengo ese enlace a mano. –

0

Hay otra solución que siempre va a funcionar, aunque con una pequeña salvedad:

int? nullableInt = null; 
var t2 = db.tests.Where(x => object.Equals(x.NullableInt, nullableInt)).ToList(); 

Cuando el valor es nulo y ou obtendrá el IS NULL consulta adecuada, sin embargo, cuando no es nulo obtendrá algo como:

SELECT ... 
WHERE ([t0].[NullableInt] IS NOT NULL) AND ([t0].[NullableInt] = @p0) 

Obviamente tiene una condición extra (la fuente de la que es un poco desconcertante). Dicho esto, el optimizador de consultas de SQL Server debería detectar eso, ya que @ p0 es un valor no nulo, la primera condición es un superconjunto y cortará la cláusula where.

+0

Eso puede funcionar en LINQ-to-SQL (I have 't probado) pero definitivamente * no * funciona en EF4. Todavía genera el mismo viejo = @param donde @param está configurado como nulo –

+0

Ah, entonces lo "arreglaron";). Sí, en L2S funciona. – mmix

0

Would haciendo:

var t2 = db.tests.Where(x => x.NullableInt == nullableInt ?? null).ToList(); 

trabajo?

Parece una completa locura.

+0

Locura de hecho, y no, no funciona. Traté de poner en el SQl generado, pero sigue fallando, supongo que está protegiendo contra algún tipo de ataque de inyección –

2

tl; dr

Si utiliza DbContext en EF6 este es fijo.

Si está utilizando EF5 (u ObjectContext en EF6) necesita establecer ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior en verdadero. Para hacer esto en DbContext, use esto:

((IObjectContextAdapter)db).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true; 

.

Más detalles

La causa principal de este problema es una diferencia en la forma en la base de datos se comparan los valores nulos y la forma en C# compara los valores nulos. Como escribe su consulta en C#, quiere usar la semántica de C#.

En EF5 introdujimos ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior, que le permitió optar por usar la semántica de C# en lugar de la semántica de la base de datos. El valor predeterminado es falso (para que las consultas existentes no comiencen mágicamente a devolver resultados diferentes cuando se actualiza a EF5). Pero puede establecerlo en verdadero y sus consultas devolverán filas.

Si está utilizando DbContext en EF5 que tienen que bajar a la ObjectContext para configurarlo:

((IObjectContextAdapter)db).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true; 

Si está utilizando EF6, a continuación, que ya esté configurado como true en DbContext por lo que son buenos para ir . Decidimos que esto causa tanta confusión que valió la pena tener el impacto potencial en las consultas existentes.

+0

Gracias Rowan, esto fue muy útil. – Eric

Cuestiones relacionadas