2008-10-24 8 views
9

Descargo de responsabilidad: He resuelto el problema usando Expresiones de System.Linq.Expressions, pero sigo buscando una forma mejor/más fácil.Cláusula dynamic where en LINQ - con nombres de columna disponibles en tiempo de ejecución

considere la siguiente situación:

var query = 
    from c in db.Customers 
    where (c.ContactFirstName.Contains("BlackListed") || 
      c.ContactLastName.Contains("BlackListed") || 
      c.Address.Contains("BlackListed")) 
    select c; 

Las columnas/atributos que necesitan ser comprobados contra el término en la lista negra sólo están disponibles para mí en tiempo de ejecución. ¿Cómo puedo generar esta cláusula dynamic where?

Una complicación adicional es que la colección Queryable (db.Customers anterior) se escribe en un Queryable de la clase base de 'Customer' (diga 'Person') y, por lo tanto, escribir c.Address como se indica anteriormente no es una opción .

+4

Me gustaría ver su solución Expressions, ¿hay alguna posibilidad de que agregue su respuesta? Aclamaciones. – Kev

+0

Consulte esta [pregunta] (http://stackoverflow.com/questions/30879/is-there-a-pattern-using-linq-to-dynamically-create-a-filter) y mi respuesta posterior con respecto a consultas dinámicas LINQ – Geoff

Respuesta

7
var query = from C in db.Customers select c; 

if (seachFirstName) 
     query = query.Where(c=>c.ContactFirstname.Contains("Blacklisted")); 

if (seachLastName) 
     query = query.Where(c=>c.ContactLastname.Contains("Blacklisted")); 

if (seachAddress) 
     query = query.Where(c=>c.Address.Contains("Blacklisted")); 

Tenga en cuenta que no son mutuamente excluyentes.

0

Dado que esto no es LINQ to Objects, sino más bien LINQ to SQL, no tiene otra alternativa además de usar Expressions o un procedimiento almacenado.

13

@Geoff tiene la mejor opción, solo Dynamic LINQ.

Si quiere seguir el camino de construir consultas en tiempo de ejecución utilizando Lambda aunque yo recomiendo que utilice el PredicateBuilder (http://www.albahari.com/nutshell/predicatebuilder.aspx) y tener algo como esto:

Expression<Fun<T,bool>> pred = null; //delcare the predicate to start with. Note - I don't know your type so I just used T 
if(blacklistFirstName){ 
    pred = p => p.ContactFirstName.Contains("Blacklisted"); 
} 
if(blacklistLastName){ 
    if(pred == null){ 
    pred = p => p.ContactLastName.Contains("Blacklisted"); //if it doesn't exist just assign it 
    }else{ 
    pred = pred.And(p => p.ContactLastName.Contains("Blacklisted"); //otherwise we add it as an And clause 
    } 
} 

Y así sucesivamente para todos las columnas que quieres incluir Cuando se llega a la consulta sólo necesita algo como esto:

var results = db.Customers.Where(pred).Select(c => c); 

He utilizado este para hacerlo construcción de LINQ para la búsqueda, donde hay alrededor de 20 opciones diferentes y produce muy buena SQL.

+1

¿No debería compilarse el predicado? – clklachu

2

Puede activar y desactivar sus cláusulas where usando algunas expresiones lógicas.

//Turn on all where clauses 
bool ignoreFirstName = false; 
bool ignoreLastName = false;; 
bool ignoreAddress = false; 

//Decide which WHERE clauses we are going to turn off because of something. 
if(something) 
    ignoreFirstName = true; 

//Create the query 
var queryCustomers = from c in db.Customers 
    where (ignoreFirstName || (c.ContactFirstName.Contains("BlackListed"))) 
    where (ignoreLastName || (c.ContactLastName.Contains("BlackListed"))) 
    where (ignoreAddress || (c.Address.Contains("BlackListed")) 
    select j; 

Si ignoreFirstName es cierto en la consulta entonces la condición del otro lado de la declaración o se ignorará.

Cuestiones relacionadas