Запрос C# linq — Где с несколькими и

#c# #linq

Вопрос:

Я пытаюсь выполнить запрос с помощью EF. Пользователь может использовать до 3 поисковых слов, но они не требуются. Как написать запрос EF, который будет работать как И для всех используемых поисковых слов, но сможет удалить И для любого пустого поискового слова?

Например, я хочу, чтобы следующие два элемента возвращали первые два элемента в массиве для s1=» мобильный», s2= » и s3=»ноутбук». Он ничего не возвращает. Он должен вернуть первые два, если s2 изменен на s2= «берк».

Пример:

 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) amp;amp; s.ToLower().Contains(s1)) 
                                    amp;amp; (!string.IsNullOrEmpty(s2) amp;amp; s.ToLower().Contains(s2))
                                    amp;amp; (!string.IsNullOrEmpty(s3) amp;amp; s.ToLower().Contains(s3))
                                orderby s
                               select s.ToUpper();

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

Комментарии:

1. @Calculuswhiz Я использую базу данных в своем приложении, но изменил ее на массив, чтобы упростить вопрос

Ответ №1:

Вместо того, чтобы пытаться написать один where оператор, вы можете при необходимости расширить существующий IQueryable<T> (или IEnumerable<T> , как в нашем примере кода) Where , связав операторы в цепочку.

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

Where Такая цепочка эквивалентна «соединению» всех предикатов вместе.

ИЗМЕНИТЬ:
Чтобы уточнить, почему ваша конкретная реализация не работает, это потому, что ваши amp;amp; операторы неверны для данного варианта использования.

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

Помните , что для этого amp;amp; требуются как левые, так и правые операторы true , поэтому в вашем случае !string.IsNullOrEmpty(s2) amp;amp; s.ToLower().Contains(s2) это означает, что s2 всегда должно быть не-пусто/пусто.

Комментарии:

1. Я сделал что-то подобное, но это не возвращает результаты со всеми поисковыми запросами. Для этого нужны s1 И s2. Это вернет результаты, если s1.Содержит == истина и s2.Содержит == ложь. Я думаю, что я мог бы очистить результирующий набор, если ничего не будет возвращено ни для одного из содержащихся.

2. Нет, это будет работать так, как вам нужно, если оба s1 и s2 НЕ пусты, это гарантирует, что он получит только результаты, содержащие оба s1 и s2 . Для приведенного вами примера вы должны использовать (IsNullOrEmpty(s1) || x.Contains(s1)) amp;amp; (IsNullOrEmpty(s2) || x.Contains(s2)) amp;amp; ...

3. @Heinrich Я привел пример, демонстрирующий, почему созданная мной реализация принципиально отличается от вашей, однако при редактировании я предоставил замену вашей логике, если вы захотите продолжить свой формат.

Ответ №2:

Пожалуйста, подумайте об этом:

 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 amp;amp; s.ToLower().Contains(s1))
                       amp;amp; (s2 != null amp;amp; s.ToLower().Contains(s2))
                       amp;amp; (s3 != null amp;amp; s.ToLower().Contains(s3))
                    orderby s
                    select s.ToUpper();

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

Ответ №3:

Если вы используете массив или список вместо нескольких строк, вы можете сделать что-то вроде

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

Это также более гибко, так как у вас может быть любое количество поисковых слов, без изменения запроса.