Home > Enterprise >  C# linq query - Where with multiple ANDs
C# linq query - Where with multiple ANDs

Time:09-17

I am trying to query using EF. The user can use up to 3 search words but they are not required. How do I write an EF query that will work as an AND for all of the search words that are used but be able to remove an AND for any search word that is empty?

Example, I want the following to return the first two elements in the array for s1='mobile', s2='', and s3='laptop'. It's not returning any. It should return the first two if s2 is changed to s2='burke'.

Example:

using System;
using System.Linq;
public class Simple {
  public static void Main() {
    string[] names = { "Burke laptop mobile", "laptop burke mobile", "Computer Laptop", 
                       "Mobile", "Ahemed", "Sania", 
                       "Kungada", "David","United","Sinshia" };

//search words
    string s1 = "mobile";
    string s2 = "";
    string s3 = "laptop";
    
      var  query = from s in names 
                               where (!string.IsNullOrEmpty(s1) && s.ToLower().Contains(s1)) 
                                    && (!string.IsNullOrEmpty(s2) && s.ToLower().Contains(s2))
                                    && (!string.IsNullOrEmpty(s3) && s.ToLower().Contains(s3))
                                orderby s
                               select s.ToUpper();

    foreach (string item in query)
      Console.WriteLine(item);
  }
}

CodePudding user response:

Instead of trying to write a single where statement, you can optionally extend an existing IQueryable<T> (or IEnumerable<T> like our code sample would be using) by chaining Where statements.

var query = names;

if (!string.IsNullOrEmpty(s1))
{
    query = query.Where(x => x.Contains(s1));
}

if (!string.IsNullOrEmpty(s2))
{
    query = query.Where(x => x.Contains(s2));
}

// ... (or make a foreach loop if s1,s2,s3 were an array.

var results = query.OrderBy(x => x).Select(x => x.ToUpper());

Chaining Where like this is equivalent to "anding" all where predicates together.

EDIT:
To update why your specific implementation doesn't work is because your && operators are incorrect for the given use-case.

(string.IsNullOrEmpty(s1) || s.ToLower().Contains(s1)) &&
(string.IsNullOrEmpty(s2) || s.ToLower().Contains(s2)) &&
(string.IsNullOrEmpty(s3) || s.ToLower().Contains(s3))

Remember that && requires both left and right statements to be true, so in your case !string.IsNullOrEmpty(s2) && s.ToLower().Contains(s2) this is saying that s2 must always be not-empty/null.

CodePudding user response:

Please consider this:

using System;
using System.Linq;
public class Simple {
  public static void Main() {
        string[] names = { "Burke laptop mobile", "laptop burke mobile", "Computer Laptop",
                       "Mobile", "Ahemed", "Sania",
                       "Kungada", "David","United","Sinshia" };

        //search words
        string s1 = "mobile";
        string s2 = "";
        string s3 = "laptop";

        var query = from s in names
                    where (s1 != null && s.ToLower().Contains(s1))
                       && (s2 != null && s.ToLower().Contains(s2))
                       && (s3 != null && s.ToLower().Contains(s3))
                    orderby s
                    select s.ToUpper();

    foreach (string item in query)
      Console.WriteLine(item);
  }
}

CodePudding user response:

If you use an array or list instead of multiple strings, you could do something like

List<string> searchWords = new List<string>
{
    "mobile",
    "",
    "laptop"
};

var query = names
    .Where(n => searchWords
        .Where(s => !string.IsNullOrEmpty(s))
        .All(s => n.ToLower().Contains(s)))
    .Select(n => n.ToUpper())
    .OrderBy(n => n);

This also is more flexible, as you can have any number of search words, without changing the query.

  • Related