I have a complex search function that allows the user to select from a list of fields, then choose a search value and also a modifier. For example if this was a shopping cart, the user is searching products and can search products matching:
Name contains "ball" Price less than "5.00" Shipping out of "United States"
etc..
My problem is, I have 25 different fields to search on, some are complex relating to child and grandchild objects. So for each field I have an if structure like:
if (mod == "!=")
{
allInvestigators = allInvestigators.Where(i => !i.Indicators.Any(j => j.Title.ToLower().Contains(txtVal)));
}
else if (mod == "==")
{
allInvestigators = allInvestigators.Where(i => i.Indicators.Any(j => j.Title.ToLower() == txtVal));
}
else
{
allInvestigators = allInvestigators.Where(i => i.Indicators.Any(j => j.Title.ToLower().Contains(txtVal)));
}
So to make it clear, the user can pick a field, a search modifier (==, <, >, !=) and can use several of these filters in one search! Does anyone have any ideas on how to shrink this code?
UPDATE THis is where I am now..
allInvestigators = allInvestigators.Where(i =>
(i.Address.State.ToLower().Contains(txtVal) && mod == "=") ||
(i.Address.State.ToLower() == txtVal && mod == "==") ||
(i.Address.State.ToLower() != txtVal && mod == "!=")
);
You could try putting the field queries into list of variables and ten being able to cycle through them and applying them properly. Not full code, just for inspiration:
Expression<Func<Item, Boolean>> expr = j => j.Title.ToLower().Contains(txtVal);
allInvestigators = allInvestigators.Where(i => !i.Indicators.AsQueryable().Any(expr));
Take a look at PredicateBuilder that is described in "C# 4.0/5.0 in a Nutshell"
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T> () { return f => true; }
public static Expression<Func<T, bool>> False<T> () { return f => false; }
public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
}
It can be used to build Expression/ Specification first.
You can find examples of AndSpecification
, OrSpecification
, NotSpecification
in the blog post Specifications Pattern with LINQ that are similar to PredicateBuilder
idea.
You can use String.Equals
allInvestigators = allInvestigators.Where(i =>
(i.Address.State.ToLower().Contains(txtVal) && mod == "=") ||
(i.Address.State.Equals(txtVal, StringComparison.CurrentCultureIgnoreCase) && mod == "==") ||
(!i.Address.State.Equals(txtVal, StringComparison.CurrentCultureIgnoreCase) && mod == "!=")
);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.