Мы работаем над программой просмотра журналов. Использование будет иметь возможность фильтровать по пользователю, серьезность и т.д. В Sql-дни я бы добавил к строке запроса, но я хочу сделать это с Linq. Как я могу условно добавить where-clauses?
Условные запросы Linq
Ответ 1
если вы хотите только фильтровать, если определенные критерии переданы, выполните что-то вроде этого
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);
Таким образом, ваше дерево выражений будет именно тем, что вы хотите. Таким образом, созданный SQL будет именно тем, что вам нужно, и не что иное.
Ответ 2
Если вам нужно отфильтровать базу в списке/массиве, используйте следующее:
    public List<Data> GetData(List<string> Numbers, List<string> Letters)
    {
        if (Numbers == null)
            Numbers = new List<string>();
        if (Letters == null)
            Letters = new List<string>();
        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();
    }
		Ответ 3
Я закончил использовать ответ, похожий на Daren's, но с интерфейсом IQueryable:
IQueryable<Log> 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();
Это создает запрос перед удалением базы данных. Команда не будет работать до конца .ToList() в конце.
Ответ 4
Когда дело доходит до условного linq, я очень люблю шаблон фильтров и труб. 
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
В основном вы создаете метод расширения для каждого случая фильтра, который принимает IQueryable и параметр.
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
    return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}
		Ответ 5
Другой вариант - использовать что-то вроде PredicateBuilder, обсуждаемого здесь здесь. Он позволяет писать код следующим образом:
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;
Обратите внимание, что у меня есть это только для работы с Linq 2 SQL. EntityFramework не реализует Expression.Invoke, который необходим для работы этого метода. У меня есть вопрос по этому вопросу здесь.
Ответ 6
Выполнение этого действия:
bool lastNameSearch = true/false; // depending if they want to search by last name,
с этим в выражении where:
where (lastNameSearch && name.LastNameSearch == "smith")
означает, что при создании окончательного запроса, если lastNameSearch is false, запрос полностью опустит любой SQL для поиска имени.
Ответ 7
 Я решил это с помощью метода расширения, позволяющего условно включить LINQ в середине беглого выражения. Это устраняет необходимость разбивать выражение на операторы if.
 Метод расширения .If():
public static IQueryable<TSource> If<TSource>(
        this IQueryable<TSource> source,
        bool condition,
        Func<IQueryable<TSource>, IQueryable<TSource>> branch)
    {
        return condition ? source : branch(source);
    }
 Это позволяет вам сделать это:
return context.Logs
     .If(filterBySeverity, q => q.Where(p => p.Severity == severity))
     .If(filterByUser, q => q.Where(p => p.User == user))
     .ToList();
  Здесь также версия IEnumerable<T> которая будет обрабатывать большинство других выражений LINQ:
public static IEnumerable<TSource> If<TSource>(
    this IEnumerable<TSource> source,
    bool condition,
    Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
    {
        return condition ? source : branch(source);
    }
		Ответ 8
Это не самая красивая вещь, но вы можете использовать выражение лямбда и передать свои условия в случае необходимости. В TSQL я делаю много следующих действий, чтобы сделать параметры необязательными:
WHERE Поле = @FieldVar ИЛИ @FieldVar IS NULL
Вы можете дублировать один и тот же стиль со следующей лямбдой (пример проверки подлинности):
MyDataContext db = new MyDataContext();
void RunQuery (строка param1, строка 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);
Пользователь foundUser = db.Users.SingleOrDefault(checkUser);
}
Ответ 9
Недавно у меня было подобное требование, и в конце концов я нашел это в MSDN. Примеры CSharp для Visual Studio 2008
Классы, включенные в образец загрузки DynamicQuery, позволяют создавать динамические запросы во время выполнения в следующем формате:
var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
Используя это, вы можете построить строку запроса динамически во время выполнения и передать ее в метод Where():
string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; 
var q = from c in db.Customers.Where(queryString, null)
        orderby c.CompanyName
        select c;
		Ответ 10
Просто используйте С# && & Оператор:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
Изменить: Ах, нужно внимательно прочитать. Вы хотели знать, как условно добавлять дополнительные предложения. В этом случае я понятия не имею.:) То, что я бы сделал, это просто подготовить несколько запросов и выполнить правильный вариант, в зависимости от того, что мне нужно.
Ответ 11
Вы можете использовать внешний метод:
var results =
    from rec in GetSomeRecs()
    where ConditionalCheck(rec)
    select rec;
...
bool ConditionalCheck( typeofRec input ) {
    ...
}
Это будет работать, но не может быть разбито на деревья выражений, что означает, что Linq to SQL будет запускать контрольный код для каждой записи.
В качестве альтернативы:
var results =
    from rec in GetSomeRecs()
    where 
        (!filterBySeverity || rec.Severity == severity) &&
        (!filterByUser|| rec.User == user)
    select rec;
Это может работать в деревьях выражений, то есть Linq to SQL будет оптимизирован.
Ответ 12
Ну, как я думал, вы могли бы включить условия фильтра в общий список Predicates:
    var list = new List<string> { "me", "you", "meyou", "mow" };
    var predicates = new List<Predicate<string>>();
    predicates.Add(i => i.Contains("me"));
    predicates.Add(i => i.EndsWith("w"));
    var results = new List<string>();
    foreach (var p in predicates)
        results.AddRange(from i in list where p.Invoke(i) select i);               
Это приводит к списку, содержащему "me", "meyou" и "mow".
Вы можете оптимизировать это, выполнив foreach с предикатами в совершенно другой функции, которая ORs все предикаты.
Ответ 13
Вы можете создать и использовать этот метод расширения
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate)
{
    return isToExecute ? source.Where(predicate) : source;
}