2008-10-24 6 views
9

Avertissement: J'ai résolu le problème en utilisant Expressions de System.Linq.Expressions, mais je suis toujours à la recherche d'un moyen meilleur/plus facile.Clause dynamic where dans LINQ - avec les noms de colonnes disponibles au moment de l'exécution

la situation suivante:

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

Les colonnes/attributs qui doivent être vérifiés contre le terme ne sont disponibles que sur la liste noire pour moi lors de l'exécution. Comment générer cette clause dynamique where? Une complication supplémentaire est que la collection Queryable (db.Customers ci-dessus) est tapée à une requête de la classe de base de 'Customer' (disons 'Person'), et écrire c.Address comme ci-dessus n'est pas une option .

+4

Je serais intéressé de voir votre solution Expressions, une chance d'ajouter à votre réponse? À votre santé. – Kev

+0

Voir cette [question] (http://stackoverflow.com/questions/30879/is-there-a-pattern-using-linq-to-dynamically-create-a-filter) et ma réponse ultérieure concernant les requêtes dynamiques LINQ – Geoff

Répondre

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")); 

Notez qu'ils ne s'excluent pas mutuellement.

0

Comme il ne s'agit pas de LINQ to Objects, mais de LINQ to SQL, vous n'avez pas d'autre choix que d'utiliser des expressions ou une procédure stockée.

13

@Geoff a la meilleure option, juste Dynamic LINQ.

Si vous voulez aller dans le sens des requêtes de construction lors de l'exécution en utilisant Lambda si je recommendons que vous utilisez le PredicateBuilder (http://www.albahari.com/nutshell/predicatebuilder.aspx) et ont quelque chose comme ceci:

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 
    } 
} 

Et ainsi de suite pour tous les colonnes que vous souhaitez inclure. Lorsque vous arrivez à votre requête, vous avez juste besoin de quelque chose comme ceci:

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

Je l'ai utilisé pour faire ce bâtiment de LINQ pour la recherche où il y a environ 20 options différentes et il produit vraiment bon SQL.

+1

Le prédicat ne devrait-il pas être compilé? – clklachu

2

Vous pouvez activer et désactiver vos clauses where à l'aide de certaines expressions logiques.

//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 est vrai dans la requête, la condition de l'autre côté de la déclaration ou sera ignorée.

Questions connexes