2010-03-12 15 views
7

Quiero generar esta sentencia SQL en LINQ:LINQ a SQL IN/Contiene() para anulable <T>

select * from Foo where Value in (1, 2, 3) 

El poco complicado parece ser que el valor es una columna que permite valores nulos.

El código LINQ equivalente parecería ser:

IEnumerable<Foo> foos = MyDataContext.Foos; 
IEnumerable<int> values = GetMyValues(); 
var myFoos = from foo in foos 
      where values.Contains(foo.Value) 
      select foo; 

Esto, por supuesto, no se compila, ya que es un foo.Valueint? y values se escribe a int.

He intentado esto:

IEnumerable<Foo> foos = MyDataContext.Foos; 
IEnumerable<int> values = GetMyValues(); 
IEnumerable<int?> nullables = values.Select(value => new Nullable<int>(value)); 
var myFoos = from foo in foos 
      where nullables.Contains(foo.Value) 
      select foo; 

... y esto:

IEnumerable<Foo> foos = MyDataContext.Foos; 
IEnumerable<int> values = GetMyValues(); 
var myFoos = from foo in foos 
      where values.Contains(foo.Value.Value) 
      select foo; 

Ambas versiones me dan los resultados que cabe esperar, pero no generan el SQL quiero . Parece que están generando resultados de tabla completa y luego haciendo el filtrado Contiene() en memoria (es decir: en LINQ simple, sin -to-SQL); no hay una cláusula IN en el registro DataContext.

¿Hay alguna forma de generar un SQL IN para tipos anulables?

NOTA

Como resultado, el problema que tenía no tenía nada que ver Contiene o anulable, por lo que la redacción de mi pregunta es en gran medida irrelevante. Ver la respuesta aceptada de @Nick Craver para más detalles.

Respuesta

14

Esto debería funcionar por su ejemplo:

IEnumerable<int> values = GetMyValues(); 
var myFoos = from foo in MyDataContext.Foos; 
      where values.Contains(foo.Value.Value) 
      select foo; 

casting como IEnumerable<T> desde el principio significa la ejecución estará fuera de SQL, en lugar llamar al IQueryable<Foo> directamente. Si echas como IEnumerable y lo usas en una consulta, obtiene MyDataContext.Foos y luego usa ese iterador y ejecuta el resto de la consulta en C# en lugar de hacerlo en SQL.

Si desea ejecutar en SQL, no lo use como IEnumerable en ningún momento del proceso. El efecto es el mismo que usar MyDataContext.Foos.AsEnumerable() en la consulta.

+0

Guau, no me di cuenta de que el uso de las referencias ha marcado una diferencia (sin duda debido al uso de métodos de extensión escritos específicamente). Eso es desafortunado desde el punto de vista de OOP. Sin embargo, resolvió mi problema. ¡Gracias! –