Como você adiciona dinâmico 'onde' cláusulas a uma consulta LINQ?
Pergunta
Eu tenho uma tabela de usuários com uma máscara de bits que contém as funções do usuário. A consulta LINQ abaixo retorna todos os usuários cujas funções incluem 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;
Eu gostaria de reescrever isso no método abaixo para retornar todos os usuários das funções dadas para que eu possa reutilizá -lo:
private List<User> GetUsersFromRoles(uint[] UserRoles) {}
Algum indicador sobre como criar minha consulta dinamicamente? Obrigado
Solução
Você pode usar o PredicateBuilder classe.
PredicateBuilder foi lançado no Pacote linqkit nuget
O Linqkit é um conjunto gratuito de extensões para os usuários do LINQ para SQL e Entity Framework.
Outras dicas
Supondo que seus valores de UserRoles sejam mesmas máscaras de bits, algo como esse funcionaria?
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);
}
Provavelmente há uma sintaxe LINQ agradável que funcionará no lugar dos loops, mas o conceito deve ser o mesmo.
Existem algumas maneiras de fazer isso:
Bibliotecas de consulta dinâmica Linq:http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Expressão árvores e expressões Lamda:http://msdn.microsoft.com/en-us/library/bb882637.aspx
Aqui está uma maneira de adicionar um número variável de Onde Cláusulas para sua consulta LINQ. Observe que não toquei na sua lógica de máscara de bits, acabei de me concentrar no múltiplo Ondes.
// 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();
}
Editar: na verdade, isso vai E a Onde cláusulas e você queria OU eles. A abordagem a seguir (uma junção interna) trabalha no LINQ para objetos, mas não pode ser traduzida para SQL com LINQ para SQL:
var result = from user in Users
from role in UserRoles
where (user.UserRolesBitmask & role) == role
select user;
Como é isso? Não é o LINQ dinâmico, mas atinge o objetivo.
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;
}
O parâmetro userroles deve ser fornecido, no entanto, como uma máscara de bits, em vez de matriz.