112 votes

Linq to SQL : comment faire "where [column] in (list of values)" ?

J'ai une fonction dans laquelle je reçois une liste d'identifiants et je dois renvoyer la liste correspondant à une description associée à l'identifiant. Par exemple :

public class CodeData
{
    string CodeId {get; set;}
    string Description {get; set;}
}

public List<CodeData> GetCodeDescriptionList(List<string> codeIDs)
    //Given the list of institution codes, return a list of CodeData
    //having the given CodeIds
}

Donc, si je devais créer moi-même le sql pour cette opération, je ferais simplement quelque chose comme ce qui suit (où la clause in contient toutes les valeurs de l'argument codeIds) :

Select CodeId, Description FROM CodeTable WHERE CodeId IN ('1a','2b','3')

Dans Linq to Sql, je n'arrive pas à trouver l'équivalent de la clause "IN". La meilleure que j'ai trouvée jusqu'à présent (qui ne fonctionne pas) est la suivante :

 var foo = from codeData in channel.AsQueryable<CodeData>()
           where codeData.CodeId == "1" || codeData.CodeId == "2"
           select codeData;

Le problème est que je ne peux pas générer dynamiquement une liste de clauses "OR" pour linq to sql, car elles sont définies au moment de la compilation.

Comment réaliser une clause where qui vérifie qu'une colonne se trouve dans une liste dynamique de valeurs en utilisant Linq to Sql ?

176voto

Jon Skeet Points 692016

Utilisez

where list.Contains(item.Property)

Ou dans votre cas :

var foo = from codeData in channel.AsQueryable<CodeData>()
          where codeIDs.Contains(codeData.CodeId)
          select codeData;

Mais vous pourriez tout aussi bien le faire en notation par points :

var foo = channel.AsQueryable<CodeData>()
                 .Where(codeData => codeIDs.Contains(codeData.CodeId));

1 votes

Comment utiliser dans le cas où CodeId est un Integer ?

3 votes

@KiranSolkar : Alors vraisemblablement codeIDs serait un List<int> et tout irait bien.

0 votes

@JonSkeet N'est-ce pas sensible à la casse ? Si codeIDs est une liste de chaînes en majuscules et que codeData.codeId est une chaîne en minuscules, cela échouera.

29voto

Nick DeMayo Points 488

Vous pourriez aussi utiliser :

List<int> codes = new List<int>();

codes.add(1);
codes.add(2);

var foo = from codeData in channel.AsQueryable<CodeData>()
          where codes.Any(code => codeData.CodeID.Equals(code))
          select codeData;

1 votes

J'ai dû utiliser ceci car notre implémentation de IQToolkit ne supporte pas .Contains().

1voto

DCShannon Points 1975

J'avais utilisé la méthode décrite dans la réponse de Jon Skeet, mais j'ai eu l'idée d'en utiliser une autre. Concat . El Concat a donné des résultats légèrement meilleurs lors d'un test limité, mais c'est un peu compliqué et je vais probablement m'en tenir à la méthode Contains ou peut-être que j'écrirai une méthode d'aide qui le fera pour moi. Quoi qu'il en soit, voici une autre option si quelqu'un est intéressé :

La méthode

// Given an array of id's
var ids = new Guid[] { ... };

// and a DataContext
var dc = new MyDataContext();

// start the queryable
var query = (
    from thing in dc.Things
    where thing.Id == ids[ 0 ]
    select thing 
);

// then, for each other id
for( var i = 1; i < ids.Count(); i++ ) {
    // select that thing and concat to queryable
    query.Concat(
        from thing in dc.Things
        where thing.Id == ids[ i ]
        select thing
    );
}

Test de performance

Ce n'était pas du tout scientifique. J'imagine que la structure de votre base de données et le nombre d'identifiants impliqués dans la liste ont un impact significatif.

J'ai mis en place un test où j'ai fait 100 essais chacun de Concat y Contains où chaque essai consistait à sélectionner 25 lignes spécifiées par une liste aléatoire de clés primaires. J'ai exécuté cette opération une douzaine de fois, et la plupart du temps, le résultat est le même. Concat est 5 à 10 % plus rapide, bien qu'une fois, la méthode Contains La méthode a gagné d'un rien.

1voto

Non Entity Framework Net Core 2

string[] names = stringsTest.name.Split('|');

if (names.Length > 1)
{
    query = query.Where(w => names.Contains(w.name));
}
else
{
    query = query.Where(w => w.name== stringsTest.name);
}

var listEntity = await query.ToListDtoAsync(stringsTest);

0voto

Deepan Raj Points 178
 var filterTransNos = (from so in db.SalesOrderDetails
                    where  ItemDescription.Contains(ItemDescription)
                            select new { so.TransNo }).AsEnumerable();    

listreceipt = listreceipt.Where(p => filterTransNos.Any(p2 => p2.TransNo == p.TransNo)).ToList();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X