248 votes

Linq to Entities - Sql "IN" clause

Dans T-SQL, vous pourriez avoir une requête comme:

 SELECT * FROM Users WHERE User_Rights IN ("Admin", "User", "Limited")
 

Comment répliqueriez-vous cela dans une requête Linq to Entities? Est-ce même possible? Merci!

373voto

BenAlabaster Points 20189

Vous devez l'activer sur il est en tête en termes de la façon dont vous êtes en train de penser à ce sujet. Au lieu de faire "" pour trouver le courant de l'élément de droits de l'utilisateur dans un ensemble prédéfini des lois applicables sur les droits d'utilisateur, vous demandez à un ensemble prédéfini de droits de l'utilisateur si elle contient l'élément actuel de la valeur applicable. C'est exactement de la même manière que vous le feriez trouver un élément dans une liste .NET.

Il y a deux manières de le faire à l'aide de LINQ, on utilise la syntaxe de la requête et l'autre utilise la méthode de la syntaxe. Essentiellement, ils sont les mêmes et pourraient être utilisés de façon interchangeable selon votre préférence:

La Syntaxe De La Requête:

var selected = from u in users
               where new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights)
               select u

foreach(user u in selected)
{
    //Do your stuff on each selected user;
}

La Syntaxe De Méthode:

var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));

foreach(user u in selected)
{
    //Do stuff on each selected user;
}

Ma préférence personnelle dans ce cas pourrait être la méthode la syntaxe parce qu'au lieu de l'assignation de la variable, j'ai pu faire la boucle foreach sur un appel anonyme comme ceci:

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}

Du point de vue syntaxique, cela ressemble plus complexe, et vous devez comprendre le concept d'expressions lambda ou les délégués à vraiment comprendre ce qu'il se passe, mais comme vous pouvez le voir, ce condense le code d'un montant équitable.

Tout se résume à votre style de codage et de préférence, tous trois de mes exemples faire la même chose un peu différemment.

Une autre façon de ne même pas utiliser LINQ, vous pouvez utiliser la même syntaxe de méthode de remplacement "où" avec "FindAll" et obtenir le même résultat, qui sera également travailler dans .NET 2.0:

foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}

21voto

Phu Chaai Points 1257

Cela devrait suffire à votre but. Il compare deux collections et vérifie si une collection a les valeurs correspondant à celles de l'autre collection

 fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
 

9voto

KristoferA Points 8036

Si vous utilisez VS2008 / .net 3.5, consultez l'astuce d'Alex James # 8: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style -queries-using-linq-à-entités.aspx

Sinon, utilisez simplement la méthode array.Contains (someEntity.Member).

8voto

abcdefghi Points 2149

Je vais aller pour Inner Join dans ce contexte. Si j'aurais utilisé des contenants, il aurait itéré 6 fois malgré le fait qu'il n'y ait qu'un seul match.

 var desiredNames = new[] { "Pankaj", "Garg" }; 

var people = new[]  
{  
    new { FirstName="Pankaj", Surname="Garg" },  
    new { FirstName="Marc", Surname="Gravell" },  
    new { FirstName="Jeff", Surname="Atwood" }  
}; 

var records = (from p in people join filtered in desiredNames on p.FirstName equals filtered  select p.FirstName).ToList(); 
 

Inconvénients de Contient

Supposons que j'ai deux objets de liste.

 List 1      List 2
  1           12
  2            7
  3            8
  4           98
  5            9
  6           10
  7            6
 

En utilisant Contient, il recherchera chaque élément de la liste 1 dans la liste 2, ce qui signifie que l'itération se produira 49 fois !!!

3voto

Matthias Meid Points 8473

J'ai aussi essayé de travailler avec un SQL-DANS-comme chose - de l'interrogation d'un Modèle de Données d'Entité. Mon approche est un générateur de chaîne de la composition d'un grand OU d'expression. C'est terriblement moche, mais j'ai peur que c'est la seule façon d'aller à droite maintenant.

Désormais bien, qui ressemble à ceci:

Queue<Guid> productIds = new Queue<Guid>(Products.Select(p => p.Key));
if(productIds.Count > 0)
{
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("{0}.ProductId = Guid\'{1}\'", entities.Products.Name, productIds.Dequeue());
    while(productIds.Count > 0)
    {
        sb.AppendFormat(" OR {0}.ProductId = Guid\'{1}\'",
          entities.Products.Name, productIds.Dequeue());
    }
}

Travailler avec les Guid dans ce contexte: Comme vous pouvez le voir ci-dessus, il y a toujours le mot "GUID" avant le GUID ifself dans la chaîne de requête fragments. Si vous n'ajoutez pas cette, ObjectQuery<T>.Where jette l'exception suivante:

Les types d'argument 'Edm.Guid " et 'Edm.Chaîne de caractères " sont incompatibles pour cette l'opération., près égale à l'expression, ligne 6, colonne 14.

Trouvé ça dans les Forums MSDN, pourrait être utile d'avoir à l'esprit.

Matthias

... à la recherche de l'avant pour la prochaine version de .NET et Entity Framework, quand tout est mieux. :)

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