2009-03-30 9 views
5

Digamos que tengo una matriz, y quiero hacer una consulta LINQ contra una varchar que devuelve cualquier registro que tenga un elemento de la matriz en cualquier parte de la varchar.LINQ para consultas LIKE de elementos de matriz

Algo así sería dulce.

string[] industries = { "airline", "railroad" }

var query = from c in contacts where c.industry.LikeAnyElement(industries) select c

¿Alguna idea?

+0

LINQ to SQL, LINQ to Entities, LINQ to Objects? – Lucas

Respuesta

5

Esto es en realidad un ejemplo que utilizo en mi presentación "Express Yourself", algo que es difícil de hacer en LINQ regular; Hasta donde yo sé, la manera más fácil de hacerlo es escribiendo el predicado manualmente. Yo uso el ejemplo siguiente (Nota que funcionaría igual de StartsWith etc):

using (var ctx = new NorthwindDataContext()) 
    { 
     ctx.Log = Console.Out; 
     var data = ctx.Customers.WhereTrueForAny(
      s => cust => cust.CompanyName.Contains(s), 
      "a", "de", "s").ToArray(); 
    } 
// ... 
public static class QueryableExt 
{ 
    public static IQueryable<TSource> WhereTrueForAny<TSource, TValue>(
     this IQueryable<TSource> source, 
     Func<TValue, Expression<Func<TSource, bool>>> selector, 
     params TValue[] values) 
    { 
     return source.Where(BuildTrueForAny(selector, values)); 
    } 
    public static Expression<Func<TSource, bool>> BuildTrueForAny<TSource, TValue>(
     Func<TValue, Expression<Func<TSource, bool>>> selector, 
     params TValue[] values) 
    { 
     if (selector == null) throw new ArgumentNullException("selector"); 
     if (values == null) throw new ArgumentNullException("values"); 
     if (values.Length == 0) return x => true; 
     if (values.Length == 1) return selector(values[0]); 

     var param = Expression.Parameter(typeof(TSource), "x"); 
     Expression body = Expression.Invoke(selector(values[0]), param); 
     for (int i = 1; i < values.Length; i++) 
     { 
      body = Expression.OrElse(body, 
       Expression.Invoke(selector(values[i]), param)); 
     } 
     return Expression.Lambda<Func<TSource, bool>>(body, param); 
    } 

} 
+0

¡Bien! (Ingrese en al menos 10 caracteres) – Lucas

4
from c in contracts 
where industries.Any(i => i == c.industry) 
select c; 

algo así como eso. usa el método de la colección.

+1

Esto arroja una excepción en LINQ to SQL. Se puede escribir como "where industries.Contains (c.industry)", que se traduce como "c.industry IN ('airline', 'railroad')", pero quiere una comparación LIKE. – Lucas

0

Desafortunadamente, como no es compatible con LINQ to SQL según aquí:

http://msdn.microsoft.com/en-us/library/bb882677.aspx

Para evitar esto, usted tendrá que escribir un procedimiento almacenado que acepte los parámetros que desea utilizar en la (s) declaración (es) similar (es) y luego llama eso de LINQ a SQL.


Cabe señalar que algunas de las respuestas sugieren el uso de Contiene. Esto no funcionará porque parece ver que toda la cadena coincide con el elemento de la matriz. Lo que se busca es que el elemento de matriz que se encuentra en el campo mismo, algo así como:

industry LIKE '%<element>%' 

Como Clark ha mencionado en un comentario, podría utilizar una llamada a IndexOf en cada elemento (lo que debería traducirse a una llamada SQL):

string[] industries = { "airline", "railroad" } 

var query = 
    from c in contacts 
    where 
     c.industry.IndexOf(industries[0]) != -1 || 
     c.industry.IndexOf(industries[1]) != -1 

Si conoce la longitud de la matriz y el número de elementos, entonces se podría difícil que el código de este. Si no lo hace, tendrá que crear la instancia de Expression basada en la matriz y el campo que está mirando.

+0

Sabía que ... mi mal ... un charindex! = -1 para cada elemento de la matriz sería suficiente. – Clark

+1

en realidad LIKE es algo compatible con LINQ to SQL. "donde c.industry.Contains (" airline ")" funciona y se traduce en "WHERE c.industry LIKE '% airline%'. Pero quiere LIKE cualquiera de los valores dados, no solo uno. – Lucas

3

IEnumerable.Contains() traduce a SQL EN como en:

WHERE 'american airlines' IN ('airline', 'railroad') -- FALSE 

String.Contains() que se traduce en SQL COMO% ...% como en:

WHERE 'american airlines' LIKE '%airline%' -- TRUE 

Si desea que los contactos donde la industria del contacto es LIKE (contiene) cualquiera de las industrias dadas, quiere combinar Any() y String.Contains() en algo como esto:

string[] industries = { "airline", "railroad" }; 

var query = from c in contacts 
      where industries.Any(i => c.Industry.Contains(i)) 
      select c; 

Sin embargo, la combinación de ambas Cualquier() y String.Contains() como este es NO apoyado en LINQ a SQL. Si el conjunto de determinadas industrias es pequeño, puede intentar algo como:

where c.Industry.Contains("airline") || 
     c.Industry.Contains("railroad") || ... 

O (aunque normalmente no se recomienda) si el conjunto de contactos es lo suficientemente pequeño, se puede llevar a todos de la base de datos y aplicar el filtro con LINQ to Objects mediante el uso de contacts.AsEnumerable() o contactos.ToList() como la fuente de la consulta anterior:

var query = from c in contacts.AsEnumerable() 
      where industries.Any(i => c.Industry.Contains(i)) 
      select c; 
1

que va a funcionar si se construye la consulta como sigue:

var query = de C en contacts.AsEnumerable() seleccione c;

query = query.Where (c => (c.Industry.Contains ("airline")) || (c.Industry.Contains ("railroad")));

solo necesita generar programáticamente la cadena anterior si los parámetros aerolínea y ferrocarril son entradas del usuario. De hecho, esto fue un poco más complicado de lo que esperaba. Ver artículo - http://www.albahari.com/nutshell/predicatebuilder.aspx

Cuestiones relacionadas