如何从几个表达式的并集组成一个表达式树

本文关键字:表达式 一个 几个 | 更新日期: 2023-09-27 17:57:44

我正在尝试构建一个IQueryable,它将由我的实体模型进行评估。我想给它传递两组lambda,并让它将所有内容组成一个更复杂的表达式树,然后将其传递到数据库中执行。

到目前为止,我拥有的是:

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中添加了几个表达式,这些表达式将它们"或"在一起。例如,如果Tint,则代码:

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

应具有与相同的结果集

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

如果没有PredicateBuilder等第三方工具,我如何使Inclusive工作?第三方工具通常很好,但我想提高我对如何在.NET.中组成表达式的理解

我还需要确保树还没有被评估,这样我就可以对数据库进行过滤。这意味着我需要生产实体框架4.0可以消费的东西。

如何从几个表达式的并集组成一个表达式树

我能想到的最接近的匹配是:

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

但我几乎可以肯定,这将是非常低效的

试试这样的东西?我不确定我没有测试过。

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

尽管已经有了一个可接受的答案,但我想指出的是,您可以使用谓词生成器将表达式与Or组合。这将使它保持为对数据库的简单查询。

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

我还没有在实体模型上测试过它,所以我不知道EF是否会支持它,但下面的方法适用于L2O。这只是Snowbear JIM编译器的代码的一个微小变化

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