LINQ PredicateBuilder multiple OR starting with PredicateBuilder.True<>

3.1k views Asked by At

I have an entity like this:

public class Product()
{
    public string Name { get; set; }
}

I want to implement a search for keywords on the Name property so that they're OR'ed. In other words, a search for:

spoon knife fork

will search for spoon or knife or fork in the Name property. I introduced a new method for PredicateBuilder on Product that looks like this:

public static Expression<Func<Product, bool>> ContainsKeywords(params string[] keywords)
{
    var predicate = PredicateBuilder.True<Product>();

    foreach (var keyword in keywords)
    {
        var temp = keyword;
        predicate = predicate.Or(x => x.Name.Contains(temp));
    }

    return predicate;
}

And I'm using it like this in one of my methods for a web service:

var keywords = Request.QueryString["q"].Split(' ');
var products = Repo.GetAll<Product>(); // get all the products from the DB
products = products.Where(Product.ContainsKeywords(keywords));

The problem I'm running into is that the user may choose not to do a keyword search, in which case the keywords array will be empty. If I start with PredicateBuilder.True<Product>(), I get a list of all Products, regardless of what keywords I put in. If I start with PredicateBuilder.False<Product>(), it works if the user inputs keywords, but if not, then the return list is empty because everything matched false.

How do I fix this in order to get my desired behavior, which is to return a list of all Products if no keyword was provided, and return a list of only the Products that matches the keywords if they were provided? I know I can do a check to see if the keywords array is empty before I do any processing, but if at all possible, I'd like PredicateBuilder to handle this case automatically.

1

There are 1 answers

3
Kris Ivanov On BEST ANSWER
var predicate = (keywords.Count() > 0)
    ? PredicateBuilder.False<Product>()
    : PredicateBuilder.True<Product>();