Условные запросы Linq - PullRequest
       56

Условные запросы Linq

85 голосов
/ 14 августа 2008

Мы работаем над средством просмотра журнала. Использование будет иметь возможность фильтрации по пользователю, серьезности и т. Д. В дни Sql я бы добавил в строку запроса, но я хочу сделать это с Linq. Как я могу условно добавить оператор where?

Ответы [ 13 ]

149 голосов
/ 14 августа 2008

, если вы хотите фильтровать только при соблюдении определенных критериев, сделайте что-то вроде этого

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 будет именно тем, что вам нужно, и не меньше.

21 голосов
/ 09 мая 2011

Если вам нужно отфильтровать базу по списку / массиву, используйте следующее:

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

    }
20 голосов
/ 21 августа 2008

Я закончил, используя ответ, похожий на ответ Дарена, но с интерфейсом 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 ().

14 голосов
/ 15 августа 2008

Когда дело доходит до условного 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;
}
4 голосов
/ 15 августа 2008

Другим вариантом будет использование чего-то вроде 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, который требуется для работы этого метода. У меня есть вопрос по этому вопросу здесь .

3 голосов
/ 11 июля 2018

Я решил эту проблему с помощью метода расширения, позволяющего условно включить 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);
    }
3 голосов
/ 13 июня 2011

Делаем это:

bool lastNameSearch = true/false; // depending if they want to search by last name,

с этим в операторе where:

where (lastNameSearch && name.LastNameSearch == "smith")

означает, что при создании окончательного запроса, если lastNameSearch равно false, в запросе будет полностью пропущен любой SQL для поиска по фамилии.

1 голос
/ 18 августа 2008

Недавно у меня было похожее требование, и в конце концов я нашел это в MSDN. CSharp Samples для 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;
1 голос
/ 14 августа 2008

Это не самая красивая вещь, но вы можете использовать лямбда-выражение и при желании передать свои условия. В TSQL я делаю много следующего, чтобы сделать параметры необязательными:

WHERE Field = @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);

}

0 голосов
/ 17 апреля 2019

Вы можете создать и использовать этот метод расширения

public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate)
{
    return isToExecute ? source.Where(predicate) : source;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...