¿Cómo agregar cláusulas dinámicas 'where' a una consulta de linq?
Pregunta
Tengo una tabla de usuario con una máscara de bits que contiene los roles del usuario. La siguiente consulta de linq devuelve todos los usuarios cuyos roles incluyen 1, 4 o 16.
var users = from u in dc.Users
where ((u.UserRolesBitmask & 1) == 1)
|| ((u.UserRolesBitmask & 4) == 4)
|| ((u.UserRolesBitmask & 16) == 16)
select u;
Me gustaría volver a escribir esto en el método que aparece a continuación para que todos los usuarios de los roles dados vuelvan a usarlo:
private List<User> GetUsersFromRoles(uint[] UserRoles) {}
¿Algún indicador sobre cómo construir dinámicamente mi consulta? Gracias
Solución
Puede usar la clase PredicateBuilder .
PredicateBuilder se ha lanzado en el paquete LINQKit NuGet
LINQKit es un conjunto gratuito de extensiones para los usuarios avanzados de LINQ to SQL y Entity Framework.
Otros consejos
Asumiendo que los valores de UserRoles son máscaras de bits, ¿funcionaría algo como esto?
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);
}
Probablemente haya una buena sintaxis de LINQ que funcione en lugar de los bucles, pero el concepto debería ser el mismo.
Hay varias formas de hacerlo:
Bibliotecas de consultas dinámicas LINQ: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Árboles de expresión & amp; Expresiones de Lamda: http://msdn.microsoft.com/en-us/library/bb882637. aspx
Esta es una forma de agregar un número variable de cláusulas where a su consulta LINQ. Tenga en cuenta que no he tocado su lógica de máscara de bits, simplemente me centré en los múltiples where 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();
}
EDITAR: En realidad, esto será Y las cláusulas where y usted quiso O . El siguiente enfoque (una unión interna) funciona en LINQ to Objects, pero no se puede traducir a SQL con LINQ to SQL:
var result = from user in Users
from role in UserRoles
where (user.UserRolesBitmask & role) == role
select user;
¿Qué tal esto? No es un linq dinámico, pero cumple el 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;
}
El parámetro UserRoles debe proporcionarse, sin embargo, como una máscara de bits, en lugar de una matriz.