2009-11-04 4 views
3

En utilisant LINQ to Entities, comment puis-je déterminer si un élément d'une liste d'ints existe dans une chaîne d'entiers délimitée par des virgules?LINQ (aux entités) - Filtrage d'éléments à l'aide d'ints

Par exemple, je veux écrire quelque chose comme ce qui suit (logiquement):

collection.Where(collection.DelimitedStringOfInts.Contains(listOfInts.AnyOfThem)) 

Aussi, je dois mentionner que je fais cela à l'aide de méthodes enchaînées LINQ, avec la chaîne délimitée dans le cadre du entité -

var listOfInts = GetListOfInts(); 
var query = from x in Db.Items select x; 
if (listOfInts != null && listOfInts.Count() > 0) 
{ 
    query = query.Where(x => x.DelimitedStringOfInts.Contains(listOfInts.AnyOfThem)); 
} 

MISE à JOUR:
en utilisant l'article référencé Alex, je mis en œuvre une solution de travail comme suit:

var query = from x in Db.Items select x; 
var listOfInts = GetListOfInts(); 
if (listOfInts != null && listOfInts.Any()) 
{ 
    //"ToListOfStrings" is a simple extension method I wrote to create a List<string> from a List<int> 
    var delimitedIds = listOfInts.ToListOfStrings(','); 
    query = query.Where(
     BuildOrExpression<DatabaseItem, string>(x => x.DelimitedStringOfInts, delimitedIds) 
     ); 
} 

Une mise à jour était nécessaire pour le "BuildOrExpression" référencé dans l'article. L'opérateur "égal à" a dû être remplacé par un opérateur "contient".

var contains = values.Select(value => 
    (Expression)Expression.Call(
        valueSelector.Body, 
        typeof(string).GetMethod("Contains"), 
        Expression.Constant(
          value, 
          typeof(TValue) 
        ) 
      ) 
    ); 
+2

Juste un détail: avez-vous besoin de faire listOfInts.Count()> 0? Ne pouvez-vous pas faire listOfInts.Any() à la place? Count() va itérer toute la liste, mais Any() vérifiera s'il y a quelque chose à itérer. –

+0

Bon conseil, merci! – Jeremy

+0

Est-ce que cela donne un faux positif sur '10' si vous utilisez "contient" et que la chaîne que vous vérifiez est '100' ou '210'. – Arnstein

Répondre

5

Jetez un oeil à ce tip, ce n'est pas exactement ce que vous demandez, mais je pense que vous pouvez modifier pour obtenir ce que vous voulez.

Alex

+0

Merci pour la référence - j'ai été en mesure de résoudre le problème en utilisant cela. J'ai mis à jour la question avec la solution de travail. – Jeremy

0

Essayez ceci:

int i = 0; 

bool exists = StringOfInts.Split(',').Any(
       s => Int32.TryParse(s, out i) && 
        listOfInts.Any(n => n == i) 
      ); 
4
DelimitedStringOfInts.Split(new char[]{','}) 
        .Select<string, int>(s => int.Parse(s)) 
        .Intersect(listOfInts).Count<int>() > 0 
+0

Vous oubliez le fait que les ints ne sont pas facilement convertibles en chaînes ... –

+0

vous avez raison, merci. – manji

+0

Tous les paramètres de type de cette requête peuvent être déduits, vous n'avez donc pas besoin de les spécifier explicitement. Certaines personnes les aiment pour être explicites (hausser les épaules), je trouve cela désagréable à regarder. –

2

convertir la chaîne à un HashSet pour une performance optimale de .Contains. .Any() devrait retourner vrai lorsque la première correspondance est trouvée.

var stringofInts = "2,3,5,9"; 
List<int> listOfInts = GetSomeListOfInts(); 

var set = new HashSet<int>(stringofInts.Split(',').Select(x => int.Parse(x))); 
listOfInts.Any(x => set.Contains(x)) 
0

Cela fera l'affaire ...

List<int> integerList = new List<int>() { 1, 2, 3, 4 }; 
string integersAsString = "1,3,5"; 


var result = integersAsString.Split(',') 
          .Select(s => Int32.Parse(s)) 
          .Where(i => integerList.Contains(i)); 

foreach (var i in result) 
    Console.WriteLine(i); // prints 1 and 3 
1

Comme vous avez compris, cette requête ne peut pas être traduit à SQL, si EF refuse de traduire la requête.

Vous aurez besoin de diviser la requête entre votre code et la base de données, en allant chercher les chaînes délimitées, puis les vérifier dans le client:

query = query.Select(x => x.DelimitedStringOfInts) 
      .ToList() // Run the query in the database now 
      .Where(ints => ints.Select(s => int.Parse(s)).Any(listOfInts.Contains)); 

Si vous préférez exécuter tout dans la base de données, je pense vous devrez utiliser sprocs ou SQL brut pour cela, ou générer dynamiquement une expression de requête, comme celle suggérée dans Alex James' answer.

Vous pouvez également accélérer la partie client avec le HashSet idea de la réponse de Jimmy.

Et, comme une autre idée (aucune idée si vous pouvez le faire) mais s'il y a une possibilité d'extension QueryProvider EF, qui permettrait de traduire un appel à List.Contains à un SQL WHERE ... IN .... Ça pourrait ne pas être facile. EF 4 aura ce intégré, d'ailleurs.

Questions connexes