Réponses:
Vous devez le mettre sur la tête en termes de la façon dont vous y pensez. Au lieu de faire "in" pour trouver les droits d'utilisateur de l'élément actuel dans un ensemble prédéfini de droits d'utilisateur applicables, vous demandez un ensemble prédéfini de droits d'utilisateur s'il contient la valeur applicable de l'élément actuel. C'est exactement de la même manière que vous trouveriez un élément dans une liste régulière dans .NET.
Il existe deux façons de procéder à l'aide de LINQ, l'une utilise la syntaxe de requête et l'autre utilise la syntaxe de méthode. Essentiellement, ils sont identiques et pourraient être utilisés de manière interchangeable selon votre préférence:
Syntaxe de 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;
}
Syntaxe de la 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 cette instance pourrait être la syntaxe de la méthode car au lieu d'affecter la variable, je pourrais faire le foreach sur un appel anonyme comme celui-ci:
foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Syntaxiquement, cela semble plus complexe, et vous devez comprendre le concept d'expressions lambda ou de délégués pour vraiment comprendre ce qui se passe, mais comme vous pouvez le voir, cela condense assez le code.
Tout dépend de votre style de codage et de vos préférences - les trois exemples font la même chose légèrement différemment.
Une autre méthode n'utilise même pas LINQ, vous pouvez utiliser la même syntaxe de méthode en remplaçant «où» par «FindAll» et obtenir le même résultat, qui fonctionnera également 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;
}
Cela devrait suffire à votre objectif. 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))
Si vous utilisez VS2008 / .net 3.5, consultez l'astuce # 8 d'Alex James: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style -queries-using-linq-to-entity.aspx
Sinon, utilisez simplement la méthode array.Contains (someEntity.Member).
Je vais opter pour Inner Join dans ce contexte. Si j'aurais utilisé Contient, il répéterait 6 fois malgré le fait qu'il n'y ait qu'une seule correspondance.
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();
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 Contains, il recherchera chaque élément de la liste 1 dans la liste 2, ce qui signifie que l'itération se produira 49 fois !!!
J'ai également essayé de travailler avec une chose semblable à SQL-IN - interroger un modèle de données d'entité . Mon approche est un constructeur de chaînes pour composer une grosse expression OR. C'est terriblement moche, mais je crains que ce soit la seule façon de procéder en ce moment.
Eh bien, cela 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());
}
}
Utilisation des GUID dans ce contexte : Comme vous pouvez le voir ci-dessus, il y a toujours le mot "GUID" avant le GUID ifself dans les fragments de chaîne de requête. Si vous n'ajoutez pas cela, ObjectQuery<T>.Where
lève l'exception suivante:
Les types d'argument 'Edm.Guid' et 'Edm.String' sont incompatibles pour cette opération., Expression presque égale, ligne 6, colonne 14.
J'ai trouvé cela dans les forums MSDN.
Matthias
... dans l'attente de la prochaine version de .NET et Entity Framework, quand tout ira mieux. :)
Une méthode alternative à la réponse BenAlabaster
Tout d'abord, vous pouvez réécrire la requête comme ceci:
var matches = from Users in people
where Users.User_Rights == "Admin" ||
Users.User_Rights == "Users" ||
Users.User_Rights == "Limited"
select Users;
Certes, c'est plus «verbeux» et pénible à écrire mais ça marche tout de même.
Donc, si nous avions une méthode utilitaire qui facilitait la création de ce type d'expressions LINQ, nous serions en affaires.
avec une méthode utilitaire en place, vous pouvez écrire quelque chose comme ceci:
var matches = ctx.People.Where(
BuildOrExpression<People, string>(
p => p.User_Rights, names
)
);
Cela crée une expression qui a le même effet que:
var matches = from p in ctx.People
where names.Contains(p.User_Rights)
select p;
Mais ce qui, plus important, fonctionne réellement contre .NET 3.5 SP1.
Voici la fonction de plomberie qui rend cela possible:
public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(
Expression<Func<TElement, TValue>> valueSelector,
IEnumerable<TValue> values
)
{
if (null == valueSelector)
throw new ArgumentNullException("valueSelector");
if (null == values)
throw new ArgumentNullException("values");
ParameterExpression p = valueSelector.Parameters.Single();
if (!values.Any())
return e => false;
var equals = values.Select(value =>
(Expression)Expression.Equal(
valueSelector.Body,
Expression.Constant(
value,
typeof(TValue)
)
)
);
var body = equals.Aggregate<Expression>(
(accumulate, equal) => Expression.Or(accumulate, equal)
);
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
Je ne vais pas essayer d'expliquer cette méthode, sinon de dire qu'elle construit essentiellement une expression de prédicat pour toutes les valeurs en utilisant valueSelector (c'est-à-dire p => p.User_Rights) et OU ces prédicats ensemble pour créer une expression pour l'ensemble prédicat
Exemple réel:
var trackList = Model.TrackingHistory.GroupBy(x => x.ShipmentStatusId).Select(x => x.Last()).Reverse();
List<int> done_step1 = new List<int>() {2,3,4,5,6,7,8,9,10,11,14,18,21,22,23,24,25,26 };
bool isExists = trackList.Where(x => done_step1.Contains(x.ShipmentStatusId.Value)).FirstOrDefault() != null;
Sérieusement? Vous n'avez jamais utilisé
where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)
Checks = NumValues * NumRows
. Comme il s'agit d'un calcul de type M * N, si l'un ou l'autre est petit, le temps pour effectuer chaque vérification requise sera également petit. J'ai ajouté la contrainte pour que cjm30305 sache comment configurer un environnement de test où montrer pourquoi sa solution est mauvaise.
where new[] { 1, 2, 3 }.Contains(x)
fait moins de comparaisons alors where (x == 1 || x == 2 || x == 3)
?