2008-10-07 12 views
23

J'ai une table utilisateur avec un masque de bits qui contient les rôles de l'utilisateur. La requête LINQ retourne ci-dessous tous les utilisateurs dont les rôles comprennent 1, 4 ou 16.Comment ajouter des clauses dynamiques 'where' à une requête linq?

var users = from u in dc.Users 
      where ((u.UserRolesBitmask & 1) == 1) 
       || ((u.UserRolesBitmask & 4) == 4) 
       || ((u.UserRolesBitmask & 16) == 16) 
      select u; 

Je voudrais réécrire ceci dans la méthode ci-dessous pour les utilisateurs retourne tous des rôles donnés donc je peux le réutiliser:

private List<User> GetUsersFromRoles(uint[] UserRoles) {} 

Des pointeurs sur la façon de générer dynamiquement ma requête? Merci

Répondre

31

Vous pouvez utiliser la classe PredicateBuilder.

PredicateBuilder a été libéré dans le LINQKit NuGet package

LINQKit est un ensemble gratuit d'extensions pour LINQ aux utilisateurs SQL et de puissance Entity Framework.

+3

Apparemment, la classe PredicateBuilder est disponible en deux versions: l'exemple de code source sur le site Web, qui est © Albahari & O'Reilly, tous droits réservés; et dans le cadre de LinqKit, qui est "sous licence libre et permissive, ce qui signifie que vous pouvez le modifier à votre guise, et l'incorporer dans votre propre logiciel commercial ou non-commercial". – Sjoerd

+0

LinqKit est disponible via NuGet. –

2

En supposant que vos valeurs UserRoles sont elles-mêmes des masques de bit, quelque chose comme cela fonctionnerait-il? Il y a probablement une bonne syntaxe LINQ qui fonctionnera à la place des boucles, mais le concept devrait être le même.

+0

Cela devrait fonctionner. Au lieu de dynamic where clause vous l'avez réduit à un seul. Et cette belle syntaxe LINQ que vous avez mentionnée pourrait être: uint roleMask = UserRoles.Aggregate (0, (combiné, rôle) => combiné | rôle); – Lucas

1

Comment ça? Ce n'est pas linq dynamique, mais accomplit le but.

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;  
} 
+0

utilisateurs.AddRange (usersInRole); –

+0

Aussi, vous devez ToList dans GetUsersFromRole –

0
private List<User> GetUsersFromRoles(uint UserRoles) { 
    return from u in dc.Users    
     where (u.UserRolesBitmask & UserRoles) != 0 
     select u; 
} 

UserRoles paramètre devrait être fourni, cependant, comme un masque de bits, au lieu de tableau.

+0

Cela retournera les utilisateurs qui correspondent à tous les rôles donnés. Sa méthode renvoie les utilisateurs qui correspondent à tous les rôles donnés. – Lucas

3

est ici une façon d'ajouter un nombre variable de clauses à votre requête LINQ. Notez que je n'ai pas touché votre logique de masque de bits, je me suis juste concentré sur le multiple s.

// 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 ET les clauses et que vous vouliez OU eux. 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 u in Users 
      from role in UserRoles 
      where (u.UserRolesBitmask & role) == role) 
      select u; 
Questions connexes