web-dev-qa-db-fra.com

Comment ajouter des clauses dynamiques «where» à une requête linq?

J'ai une table utilisateur avec un masque de bits qui contient 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;

Je voudrais réécrire ceci dans la méthode ci-dessous pour retourner tous les utilisateurs des rôles donnés afin que je puisse le réutiliser:

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

Des conseils sur la façon de créer dynamiquement ma requête? Merci

25
Nick

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 avancés de LINQ to SQL et Entity Framework.

32
ilitirit

Voici une façon d'ajouter un nombre variable de clauses where à votre requête LINQ. Notez que je n'ai pas touché à votre logique de masque de bits, je me suis concentré uniquement sur les multiples 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 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 user in Users
             from role in UserRoles
             where (user.UserRolesBitmask & role) == role
             select user;
3
Lucas

En supposant que vos valeurs UserRoles soient elles-mêmes des masques de bits, quelque chose comme ça fonctionnerait-il?

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 y a probablement une syntaxe Nice LINQ qui fonctionnera à la place des boucles, mais le concept devrait être le même.

3
Dylan Beattie

Vous pouvez procéder 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 et expressions Lamda: http://msdn.Microsoft.com/en-us/library/bb882637.aspx

3
alexmac

Comment c'est? Ce n'est pas linq dynamique, 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;    
}
1
Carlton Jenke
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 sous la forme d'un masque de bits au lieu d'un tableau.

0
Michael Damatov