Requêtes Linq Conditionnelles

Nous travaillons sur un visualiseur de journaux. L’utilisation aura la possibilité de filtrer par utilisateur, sévérité, etc. Dans les jours Sql j’appendais à la chaîne de requête, mais je veux le faire avec Linq. Comment puis-je append conditionnellement les clauses where?

Si vous voulez seulement filtrer si certains critères sont passés, faites quelque chose comme ça

var logs = from log in context.Logs select log; if (filterBySeverity) logs = logs.Where(p => p.Severity == severity); if (filterByUser) logs = logs.Where(p => p.User == user); 

Ainsi, votre arbre d’expression sera exactement ce que vous voulez. De cette façon, le SQL créé sera exactement ce dont vous avez besoin et rien de moins.

Si vous devez filtrer la base sur une liste / un tableau, utilisez ce qui suit:

  public List GetData(List Numbers, List Letters) { if (Numbers == null) Numbers = new List(); if (Letters == null) Letters = new List(); var q = from d in database.table where (Numbers.Count == 0 || Numbers.Contains(d.Number)) where (Letters.Count == 0 || Letters.Contains(d.Letter)) select new Data { Number = d.Number, Letter = d.Letter, }; return q.ToList(); } 

J’ai fini par utiliser une réponse similaire à celle de Daren, mais avec une interface IQueryable:

 IQueryable matches = m_Locator.Logs; // Users filter if (usersFilter) matches = matches.Where(l => l.UserName == comboBoxUsers.Text); // Severity filter if (severityFilter) matches = matches.Where(l => l.Severity == comboBoxSeverity.Text); Logs = (from log in matches orderby log.EventTime descending select log).ToList(); 

Cela construit la requête avant de bash la firebase database. La commande ne fonctionnera pas jusqu’à la fin de .ToList ().

En ce qui concerne le linq conditionnel, j’aime beaucoup le modèle des filtres et des tuyaux.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/

Fondamentalement, vous créez une méthode d’extension pour chaque cas de filtre qui prend en charge le paramètre IQueryable et un paramètre.

 public static IQueryable HasID(this IQueryable query, long? id) { return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query; } 

Une autre option serait d’utiliser quelque chose comme le PredicateBuilder discuté ici . Il vous permet d’écrire du code comme celui-ci:

 var newKids = Product.ContainsInDescription ("BlackBerry", "iPhone"); var classics = Product.ContainsInDescription ("Nokia", "Ericsson") .And (Product.IsSelling()); var query = from p in Data.Products.Where (newKids.Or (classics)) select p; 

Notez que je n’ai que cela pour fonctionner avec Linq 2 SQL. EntityFramework n’implémente pas Expression.Invoke, requirejs pour que cette méthode fonctionne. J’ai une question concernant ce problème ici .

Ce faisant:

 bool lastNameSearch = true/false; // depending if they want to search by last name, 

avoir ceci dans l’instruction where :

 where (lastNameSearch && name.LastNameSearch == "smith") 

signifie que lorsque la requête finale est créée, si lastNameSearch est false la requête omettra complètement tout SQL pour la recherche de nom de famille.

Ce n’est pas la plus belle chose, mais vous pouvez utiliser une expression lambda et passer éventuellement vos conditions. Dans TSQL, je fais beaucoup de choses pour rendre les parameters facultatifs:

WHERE Field = @FieldVar OU @FieldVar EST NULL

Vous pouvez dupliquer le même style avec le lambda suivant (un exemple de vérification de l’authentification):

MyDataContext db = new MyDataContext ();

annuler RunQuery (ssortingng param1, ssortingng param2, int? param3) {

Func checkUser = user =>

((param1.Length> 0)? user.Param1 == param1: 1 == 1) &&

((param2.Length> 0)? user.Param2 == param2: 1 == 1) &&

((param3! = null)? user.Param3 == param3: 1 == 1);

Utilisateur foundUser = db.Users.SingleOrDefault (checkUser);

}

J’ai eu une exigence similaire récemment et finalement trouvé cela dans le MSDN. Exemples CSharp pour Visual Studio 2008

Les classes incluses dans l’exemple DynamicQuery du téléchargement vous permettent de créer des requêtes dynamics au moment de l’exécution au format suivant:

 var query = db.Customers. Where("City = @0 and Orders.Count >= @1", "London", 10). OrderBy("CompanyName"). Select("new(CompanyName as Name, Phone)"); 

En utilisant cela, vous pouvez créer une chaîne de requête dynamicment à l’exécution et la transmettre à la méthode Where ():

 ssortingng dynamicQuerySsortingng = "City = \"London\" and Order.Count >= 10"; var q = from c in db.Customers.Where(querySsortingng, null) orderby c.CompanyName select c; 

J’ai résolu ce problème avec une méthode d’extension permettant à LINQ d’être activé conditionnellement au milieu d’une expression fluide. Cela supprime la nécessité de diviser l’expression avec des instructions if .

Méthode d’extension .If() :

 public static IQueryable If( this IQueryable source, bool condition, Func, IQueryable> branch) { return condition ? source : branch(source); } 

Cela vous permet de faire ceci:

 return context.Logs .If(filterBySeverity, q => q.Where(p => p.Severity == severity)) .If(filterByUser, q => q.Where(p => p.User == user)) .ToList(); 

Utilisez simplement l’opérateur S && de C #:

 var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical") 

Edit: Ah, besoin de lire plus attentivement. Vous vouliez savoir comment append conditionnellement des clauses supplémentaires. Dans ce cas, je n’en ai aucune idée. 🙂 Ce que je ferais probablement, c’est de préparer plusieurs requêtes et d’exécuter la bonne, en fonction de ce dont j’ai eu besoin.

Vous pouvez utiliser une méthode externe:

 var results = from rec in GetSomeRecs() where ConditionalCheck(rec) select rec; ... bool ConditionalCheck( typeofRec input ) { ... } 

Cela fonctionnerait, mais ne peut pas être décomposé en arborescences d’expression, ce qui signifie que Linq to SQL exécutera le code de vérification pour chaque enregistrement.

Alternativement:

 var results = from rec in GetSomeRecs() where (!filterBySeverity || rec.Severity == severity) && (!filterByUser|| rec.User == user) select rec; 

Cela pourrait fonctionner dans les arbres d’expression, ce qui signifie que Linq to SQL serait optimisé.

Eh bien, ce que je pensais, c’était que vous pouviez mettre les conditions de filtrage dans une liste générique de prédicats:

  var list = new List { "me", "you", "meyou", "mow" }; var predicates = new List>(); predicates.Add(i => i.Contains("me")); predicates.Add(i => i.EndsWith("w")); var results = new List(); foreach (var p in predicates) results.AddRange(from i in list where p.Invoke(i) select i); 

Cela se traduit par une liste contenant “moi”, “meyou” et “mow”.

Vous pouvez optimiser cela en effectuant le foreach avec les prédicats dans une fonction totalement différente de celle de tous les prédicats.