2009-02-04 10 views
7

J'ai une liste <string> de nombre de variables, et je veux interroger (via LINQ) une table pour trouver tous les éléments qui contiennent l'une de ces chaînes dans la colonne Texte.LINQ to SQL - sélectionnez où texte comme tableau de chaînes

essayé ce (ne fonctionne pas):

items = from dbt in database.Items 
     where (stringList.FindAll(s => dbt.Text.Contains(s)).Count > 0) 
     select dbt; 

la requête serait quelque chose comme:

select * from items where text like '%string1%' or text like '%string2%' 

Est-ce possible?

Répondre

11

Vérifiez cet article sur faire ce que vous voulez:
http://www.albahari.com/nutshell/predicatebuilder.aspx

Cela fonctionne comme un rêve. Je coupe essentiellement et collé leur code et obtenu ce retour (avec mes propres données-système bien sûr):

SELECT [t0].[Id], [t0].[DateCreated], [t0].[Name] ... 
FROM [dbo].[Companies] AS [t0] 
WHERE ([t0].[Name] LIKE @p0) OR ([t0].[Name] LIKE @p1) 

Voici le code que je courais pour la preuve de concept:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Linq.Expressions; 

namespace PredicateTest 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     DataClasses1DataContext dataContext = new DataClasses1DataContext(); 

     Program p = new Program(); 
     Program.SearchCompanies("test", "test2"); 
     var pr = from pi in dataContext.Companies.Where(Program.SearchCompanies("test", "test2")) select pi; 
    } 

    DataClasses1DataContext dataContext = new DataClasses1DataContext(); 

    public static Expression<Func<Company, bool>> SearchCompanies(
                params string[] keywords) 
    { 
     var predicate = PredicateBuilder.False<Company>(); 
     foreach (string keyword in keywords) 
     { 
      string temp = keyword; 
      predicate = predicate.Or(p => p.Name.Contains(temp)); 
     } 
     return predicate; 
    } 

} 

public static class PredicateBuilder 
{ 
    public static Expression<Func<T, bool>> True<T>() { return f => true; } 
    public static Expression<Func<T, bool>> False<T>() { return f => false; } 

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, 
                 Expression<Func<T, bool>> expr2) 
    { 
     var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>()); 
     return Expression.Lambda<Func<T, bool>> 
       (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters); 
    } 

    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, 
                 Expression<Func<T, bool>> expr2) 
    { 
     var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>()); 
     return Expression.Lambda<Func<T, bool>> 
       (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); 
    } 
} 
} 

Je d suggérer d'aller sur le site pour le code et l'explication.

(je laisse la première réponse, car il fonctionne bien si vous avez besoin d'une déclaration IN)

6

un peu nouveau à tout le jeu LINQ to SQL, mais cette syntaxe aide-t-elle?

string[] items = new string[] { "a", "b", "c", "d" }; 

var items = from i in db.Items 
      where items.Contains(p.text) 
      select i; 

Got it de:

http://blog.wekeroad.com/2008/02/27/creating-in-queries-with-linq-to-sql/

+0

Ce que devrait fonctionner –

+3

Merci pour l'idée Matthew, mais qui génère l'instruction SQL suivante:.. SELECT [T0] [Texte] DE [dbo] [Tableau] AS [t0] OÙ [t0 ] [Texte] IN (@ p0) Il recherche la colonne de texte dans chaque élément du tableau plutôt que de rechercher chaque élément du tableau dans la colonne de texte. – bjallen

1

Après avoir lu ce post, la recherche de la même solution que vous, j'ai trouvé une solution en utilisant les méthodes .Any et .All pour Linq est un bon moyen simple et élégant pour obtenir des résultats correspondants pour les tableaux.

Dans ce cas, j'utilise une entrée de recherche, séparée par des virgules à titre d'exemple. Je me fiche que le match ne soit pas dans le même cas.

var qry = Query.Split(',').Select(c => c.Trim().ToLower()); 

d'abord obtenir des données à interroger, de LINQ to SQL ou où

var search = db.tablename; 

En utilisant la syntaxe lambda pour bien le code serré, et le résultat dans les matches à .Any chaîne dans la requête soit le nom ou description dans le tableau.

search = search.Where(
    record => 
    qry.Any(q => record.Name.ToLower().Contains(q)) || 
    qry.Any(q => record.Description.ToLower().Contains(q))); 

Si vous voulez uniquement les résultats où toutes les chaînes se fait dans des tout champ, vous pouvez remplacer .Any avec .All:

search = search.Where(
    record => 
    qry.All(q => record.Name.ToLower().Contains(q)) || 
    qry.All(q => record.Description.ToLower().Contains(q))); 
0

utilisant:

string searh = "test1 test2,test3";  
data.Persons.Search(p => p.Name, search); 

fonction de recherche est:

public static IQueryable<T> Search<T>(this IQueryable<T> source, Expression<Func<T, string>> selector, string s) 
{ 
    if (string.IsNullOrEmpty(s)) 
     return source; 

    string[] str = s.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); 

    MethodInfo methodContains = typeof(string).GetMethod("Contains", new[] { typeof(string) }); 

    Expression strExpression; 
    Expression expressionContains; 
    Expression resultExpression = Expression.Empty(); 

    for (int i = 0; i < str.Length; i++) 
    { 
     strExpression = Expression.Constant(str[i].Trim(), typeof(string)); 
     expressionContains = Expression.Call(selector.Body, methodContains, strExpression); 

     if (i == 0) 
      resultExpression = expressionContains; 
     else 
      resultExpression = Expression.OrElse(resultExpression, expressionContains); 
    } 

    Expression<Func<T, bool>> lambdaExpr = Expression.Lambda<Func<T, bool>>(resultExpression, new ParameterExpression[] { selector.Parameters[0] }); 

    return source.Where(lambdaExpr); 
}