Как я могу составить дерево выражений из объединения нескольких выражений? - PullRequest
4 голосов
/ 26 мая 2011

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

Вот что у меня есть:

public class FilterManager<T>
{
    public List<Expression<Func<T, bool>>> Inclusive { get; set; }
    public List<Expression<Func<T, bool>>> Exclusive { get; set; }

    public IQueryable<T> ApplyFilters(IQueryable<T> query)
    {
        var q = query;

        Exclusive.ForEach(exp => q = q.Where(exp)); //works fine
        Inclusive.ForEach(exp => /* ??? */); 

        return q;
    }

    //ctor, etc.
}

Идея в том, что я добавляю несколько выражений к Inclusive, которые объединяют их в "Ors".Например, если T является int, код:

fm.Inclusive.Add(x => x > 1);
fm.Inclusive.Add(y => y < 5);

query = fm.ApplyFilters(query);

должен иметь такой же набор результатов, как:

query = query.Where(z => z > 1 || z < 5);

Как мне получить Inclusive дляработать без сторонних инструментов, таких как PredicateBuilder?Сторонние инструменты обычно хороши, но я хотел бы улучшить мое понимание того, как составлять выражения в .NET.

Мне также нужно убедиться, что дерево еще не будет оценено, чтобыЯ могу сделать фильтрацию по базе данных.Это означает, что мне нужно будет произвести что-то, что может потреблять Entity Framework 4.0.

Ответы [ 4 ]

3 голосов
/ 26 мая 2011

Самое близкое совпадение, которое я могу придумать, это:

public IQueryable<T> ApplyFilters(IQueryable<T> query)
{
    IQueryable<T> q;

    if (!Inclusive.Any())
        q = query;
    else
    {
        q = Enumerable.Empty<T>();
        Inclusive.ForEach(exp => q = q.Union(query.Where(exp)));
    }

    Exclusive.ForEach(exp => q = q.Where(exp));

    return q;
}

Но я почти уверен, что это будет очень неэффективно

0 голосов
/ 26 мая 2011

Я еще не тестировал его на своей модели сущностей, поэтому не знаю, будет ли он поддерживаться EF, но для L2O работает следующее. Это просто небольшое изменение по сравнению с JIM-компилятором Snowbear код:

public IQueryable<T> ApplyFilters(IQueryable<T> query)
{
    Exclusive.ForEach(exp => query = query.Where(exp));

    if (Inclusive.Count == 0)
    {
        return query;
    }

    IQueryable<T> q = Enumerable.Empty<T>().AsQueryable<T>();
    Inclusive.ForEach(exp => q = q.Union(query.Where(exp)));

    return q;
}
0 голосов
/ 26 мая 2011

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

http://www.albahari.com/nutshell/predicatebuilder.aspx

0 голосов
/ 26 мая 2011

Попробуйте что-нибудь подобное? Я не уверен, что не проверял это.

Inclusive.ForEach(exp => q = q.Union(q.Where(exp)));
...