Cláusula donde dinámica (OR) en Linq to Entities
En la publicación aquí , aprendí cómo crear una consulta dinámica utilizando la ejecución diferida de Linq. Pero la consulta en realidad utiliza una concatenación AND de la condición WHERE.
¿Cómo puedo lograr la misma consulta pero con una lógica OR?
Debido a la enumeración Flags, la consulta debe buscar Nombre de usuario , Nombre de usuario de Windows o ambos :
public User GetUser(IdentifierType type, string identifier)
{
using (var context = contextFactory.Invoke())
{
var query = from u in context.Users select u;
if (type.HasFlag(IdentifierType.Username))
query = query.Where(u => u.Username == identifier);
if (type.HasFlag(IdentifierType.Windows))
query = query.Where(u => u.WindowsUsername == identifier);
return query.FirstOrDefault();
}
}
Con PredicateBuilder de LINQKit puede crear predicados dinámicamente .
var query = from u in context.Users select u;
var pred = Predicate.False<User>();
if (type.HasFlag(IdentifierType.Username))
pred = pred.Or(u => u.Username == identifier);
if (type.HasFlag(IdentifierType.Windows))
pred = pred.Or((u => u.WindowsUsername == identifier);
return query.Where(pred.Expand()).FirstOrDefault();
// or return query.AsExpandable().Where(pred).FirstOrDefault();
Para esto es Expand
:
La canalización de procesamiento de consultas de Entity Framework no puede manejar expresiones de invocación, por lo que debe llamar a AsExpandable en el primer objeto de la consulta. Al llamar a AsExpandable, activa la clase de visitante de expresión de LINQKit que sustituye las expresiones de invocación con construcciones más simples que Entity Framework pueda entender.
O: sin ella una expresión es Invoke
d, lo que provoca una excepción en EF:
El tipo de nodo de expresión LINQ 'Invoke' no se admite en LINQ to Entities.
Adición posterior:
Existe un generador de predicados alternativo que hace lo mismo pero sin Expandir: http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/