2009-02-28 25 views
11

Tengo una tabla de cursos que necesito buscar en base a palabras clave escritas en el cuadro de búsqueda. Aquí es una consulta de ejemplo:LINQ multiple where cláusula

SELECT * FROM Courses WHERE 
Title LIKE '%word%' OR Title LIKE '%excel%' OR 
Contents LIKE '%word%' OR Contents LIKE '%excel%' 

¿Cómo puedo convertir esto en LINQ LINQ donde sería dinámicamente generar comandos donde en función de cada palabra clave.

He intentado utilizar PredicateBuilder funciona bien siempre que el campo sea VARCHAR. Para los campos "TEXTO", las comillas no se generan, lo que hace que el compilador muestre un mensaje de error. Aquí está el SQL generado por PredicateBuilder

SELECT [t0].[CoursesID], [t0].[Title], [t0].[Contents], [t0].[Active], 
FROM [dbo].[Courses] AS [t0] 
WHERE ([t0].[Title] LIKE '%word%') OR ([t0].[Contents] LIKE %word%) OR 
([t0].Title] LIKE '%excel%') OR ([t0].[Contents] LIKE %excel%) 

Note que no hay una sola cotización para el campo "Contenido", que es un campo de texto en la base de datos.

¿Hay alguna manera fácil de construir instrucción WHERE y adjuntarla con la consulta? ¿Alguien sabe cómo puedo hacer esto sin PredicateBuilder?

Gracias de antemano.

Respuesta

13

Dado que está trabajando con LINQ, supongo que está trabajando en un contexto de datos LINQ-to-SQL ¿verdad? No tengo un DataContext de repuesto por ahí para probar esto, pero esto debería darte algunas ideas.

No sé si funcionará contra el contexto de datos, pero la mayoría de estas son cosas bastante básicas (encadenando el operador OR y contiene la llamada al método) por lo que no debería causar problemas cuando la consulta traduce a SQL.

Primero crear una función personalizada que construiría mi predicado:

Func<string, Func<DataItem, bool>> buildKeywordPredicate = 
    keyword => 
     x => x.Title.Contains(keyword) 
      || x.Contents.Contains(keyword); 

Ésta es una función que toma una sola palabra clave de cadena y luego regresar otra función que toma un DataItem y comprueba contra la palabra clave.

Básicamente, si pasa en "Pila", obtendrá un predicado: x => x.Title.Contains("Stack") || x.Contents.Contains("Stack").

A continuación, ya que hay muchas palabras clave posibles y que necesita para la cadena con una operación OR, puedo crear otra función auxiliar para la cadena 2 predicados junto con un OR

Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate = 
    (pred1, pred2) => 
     x => pred1(x) || pred2(x); 

Esta función toma 2 predicados y luego únelos con una operación OR.

Tener esos 2 funciones, entonces me puedo construir mi donde predicado como esto:

foreach (var word in keywords) {    
    filter = filter == null 
     ? buildKeywordPredicate(word) 
     : buildOrPredicate(filter, buildKeywordPredicate(word)); 
} 

La primera línea dentro del bucle básicamente comprueba si el filtro es nulo. Si es así, entonces queremos que se cree un filtro de palabras clave simple para nosotros.

De lo contrario, si el filtro no es nulo, debemos encadenar los filtros existentes con una operación OR, por lo que pasamos el filtro existente y un nuevo filtro de palabra clave a buildOrPredicate para hacer justamente eso.

Y entonces ahora podemos crear la parte WHERE de la consulta:

var result = data.Where(filter); 

Pasando en el predicado complicada que sólo hemos construido.

No sé si esto será diferente al uso de PredicateBuilder pero dado que estamos posponiendo la traducción de consultas al motor LINQ-to-SQL, no debería haber ningún problema.

Pero como he dicho, no lo he probado contra un contexto de datos real, por lo que si hay algún problema puede escribir en los comentarios.

Aquí está la aplicación de consola que he construido a prueba: http://pastebin.com/feb8cc1e

Espero que esto ayude!


EDIT: Para una versión más genérica y reutilizable que consiste en utilizar adecuadamente los árboles de expresión en LINQ, echa un vistazo a el blog de Thomas Petricek: http://tomasp.net/articles/dynamic-linq-queries.aspx

+1

Esto desafortunadamente trabajar sólo para funciones. Para hacer que esto funcione con Expression Trees debes usar un truco como este: http://tomasp.net/articles/dynamic-linq-queries.aspx –

+0

¡Esa es una hazaña que hiciste allí! .. El mismo truco pero más genérico y más genial ... De todos modos, ahora soy un suscriptor de tu blog :-) – chakrit

+0

Gracias, este funcionó. http://tomasp.net/articles/dynamic-linq-queries.aspx - Tomas Petricek – Amir

0

Como el generador de predicados no conoce el tipo de base de datos de la propiedad con la que se invoca el método Contiene, supongo que esto podría ser un problema dentro de linq a sql. ¿Ha intentado con una consulta normal (no con el creador de predicados) y una columna de TEXTO con Contiene?

Cuestiones relacionadas