Comment ajouter des clauses "where" dynamiques à une requête linq?
Question
J'ai une table utilisateur avec un masque de traitement contenant les rôles de l'utilisateur. La requête linq ci-dessous renvoie tous les utilisateurs dont les rôles incluent 1, 4 ou 16.
var users = from u in dc.Users
where ((u.UserRolesBitmask & 1) == 1)
|| ((u.UserRolesBitmask & 4) == 4)
|| ((u.UserRolesBitmask & 16) == 16)
select u;
J'aimerais réécrire ceci dans la méthode ci-dessous pour renvoyer tous les utilisateurs des rôles donnés afin que je puisse le réutiliser:
private List<User> GetUsersFromRoles(uint[] UserRoles) {}
Des indications sur la manière de construire dynamiquement ma requête? Merci
La solution
Vous pouvez utiliser la classe PredicateBuilder .
PredicateBuilder a été publié dans le package LINQKit NuGet
.LINQKit est un ensemble gratuit d’extensions pour les utilisateurs expérimentés de LINQ to SQL et Entity Framework.
Autres conseils
En supposant que vos valeurs UserRoles soient elles-mêmes des masques de bits, cela pourrait-il fonctionner?
private List<User> GetUsersFromRoles(uint[] UserRoles) {
uint roleMask = 0;
for (var i = 0; i < UserRoles.Length;i++) roleMask= roleMask| UserRoles[i];
// roleMasknow contains the OR'ed bitfields of the roles we're looking for
return (from u in dc.Users where (u.UserRolesBitmask & roleMask) > 0) select u);
}
Il existe probablement une belle syntaxe LINQ qui fonctionnera à la place des boucles, mais le concept devrait être le même.
Vous pouvez le faire de plusieurs manières:
Bibliothèques de requêtes dynamiques LINQ: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Arbres d'expression & amp; Expressions Lamda: http://msdn.microsoft.com/en-us/library/bb882637. aspx
Voici un moyen d’ajouter un nombre variable de clauses où à votre requête LINQ. Notez que je n’ai pas touché à votre logique de masque de bits, je me suis concentré sur les multiples où .
// C#
private List<User> GetUsersFromRoles(uint[] UserRoles)
{
var users = dc.Users;
foreach (uint role in UserRoles)
{
users = users.Where(u => (u.UserRolesBitmask & role) == role);
}
return users.ToList();
}
EDIT: En fait, cela va ET les clauses et vous souhaitez les OU . L’approche suivante (une jointure interne) fonctionne dans LINQ to Objects mais ne peut pas être traduite en SQL avec LINQ to SQL:
var result = from user in Users
from role in UserRoles
where (user.UserRolesBitmask & role) == role
select user;
Comment ça? Ce n'est pas dynamique linq, mais atteint l'objectif.
private List<User> GetUsersFromRoles(uint[] userRoles)
{
List<User> users = new List<User>();
foreach(uint userRole in UserRoles)
{
List<User> usersInRole = GetUsersFromRole(userRole);
foreach(User user in usersInRole )
{
users.Add(user);
}
}
return users;
}
private List<User> GetUsersFromRole(uint userRole)
{
var users = from u in dc.Users
where ((u.UserRolesBitmask & UserRole) == UserRole)
select u;
return users;
}
private List<User> GetUsersFromRoles(uint UserRoles) {
return from u in dc.Users
where (u.UserRolesBitmask & UserRoles) != 0
select u;
}
Le paramètre UserRoles doit cependant être fourni en tant que masque de bits, au lieu de tableau.