2009-11-10 19 views
22

Considere esta consulta de LINQ a SQL. Es intención es tener una cadena [] de términos de búsqueda y aplicar los términos de un montón de diferentes campos en la tabla de SQL:Excepción de LINQ a SQL: la secuencia local no se puede usar en la implementación LINQ to SQL de los operadores de consulta, excepto el operador Contiene

string[] searchTerms = new string[] {"hello","world","foo"}; 
List<Cust> = db.Custs.Where(c => 
    searchTerms.Any(st => st.Equals(c.Email)) 
|| searchTerms.Any(st => st.Equals(c.FirstName)) 
|| searchTerms.Any(st => st.Equals(c.LastName)) 
|| searchTerms.Any(st => st.Equals(c.City)) 
|| searchTerms.Any(st => st.Equals(c.Postal)) 
|| searchTerms.Any(st => st.Equals(c.Phone)) 
|| searchTerms.Any(st => c.AddressLine1.Contains(st)) 
) 
.ToList(); 

genera una excepción:

secuencia local no se puede utilizar en LINQ a SQL aplicación de operadores de consulta, excepto el operador Contiene()

pregunta: ¿por qué se eleva esta excepción, y cómo se puede rewritt la consulta es para evitar esta excepción?

Respuesta

32

Reemplace los usos de Cualquiera con Contiene en su consulta. por ejemplo:

searchTerms.Contains(c.Email) 

Esto debería obtener el resultado que está buscando. Mira hacia atrás, pero es correcto: generará un operador IN para cada campo dentro de un Contiene con todos los elementos en searchTerms.

La parte AddressLine1 no funciona de esta manera- que tendrá que bucle generar las comparaciones con el mismo

c.addressLine1.Contains(...) 

Algo así como PredicateBuilder puede ser útil para esto.

+0

@nitzmahone: gracias, se echa un vistazo a PredicateBuilder, parece ¡prometedor! –

+0

Me preocuparía que la genialidad de 'PredicateBuilder' decepcionará en una implementación LinqToSql ya que algunas de las condiciones pueden no ser implementadas por el proveedor LinqToSql (el problema exacto que describe en su pregunta). –

+0

+1 para '.Contains()' - generalmente es un buen reemplazo para las ecuaciones que no son compatibles con LinqToSql. Se recomienda precaución con 'PredicateBuilder' incluso siendo una opción. –

11

Es sólo una idea (no directamente relacionada con la pregunta, pero podría ayudar a otros espectadores):

que estaba recibiendo el mismo mensaje de error ya que, a pesar de que yo estaba usando el método contains() correctamente, y Me llevó bastante tiempo descubrir que la raíz de mi problema era devolver un IEnumerable a algo que necesitaba filtrar los resultados de la consulta L2S. Una vez que cambié el tipo de devolución de la función a una IQueryable, el problema desapareció. Tiene sentido, ya que un IEnumerable no se puede filtrar más, pero un IQueryable puede.

0

Me estaba dando el mismo error, pero ninguna de las soluciones publicadas anteriormente funcionó para mí.

lo que funcionó para mí era para echar db.Custs en una lista primera, así como:

List<Cust> =db.Custs.ToList<Cust>.Where(... 

no tengo idea de por qué funcionó, pero lo hizo.

+3

Funciona en su caso porque ha pasado por alto la base de datos y está trabajando en contra de la colección, en lugar de tener el método de extensión 'Contains()' traducido a SQL. –

0

Básicamente, el error indica que está haciendo una unión entre dos colecciones, una de las cuales es una tabla de base de datos, y la otra es una matriz. LINQ no está diseñado para manejar eso - o bien ambos tienen que estar en la base de datos, o ambos en memoria (con excepción de casos especiales realizado cuando se utiliza Contains)