基于数组生成动态LINQ表达式

时间:2018-04-05 05:38:37

标签: c# .net linq linq-to-sql expression

我正在使用LINQ exprssion查询客户并按州名过滤它们。我有以下查询工作正常,直到我在statesArray中有4个项目。

public void GetCustomersForSelectedStates(string[] statesArray)
{
    var customers = _repo.GetAllCustomers();
    var filteredCustomers = from CUST in customers
    join ST in States on CT.Tag_Id equals ST.Id                       
    where CUST.ID == customer.ID  && (ST.Name == statesArray[0] ||ST.Name ==statesArray[1] || ST.Name== statesArray[2]||ST.Name =statesArray[3])

    //Do something with customers

}

我希望动态创建以下exprssion:

(ST.Name == statesArray[0] ||ST.Name ==statesArray[1] ||    
 ST.Name== statesArray[2]||ST.Name =statesArray[3])

例如,创建如下所示的dynamicQuery

var dynamicQuery = "(";
var dynamicQuery = "(";
for (int i = 0; i < statesArray.Count(); i++)
    {
        dynamicQuery += "ST.Name =="+statesArray[0];
        if(i==statesArray.Count())
        dynamicQuery+=")"
    }

然后使用类似下面的内容,

//Psuedo code
var customers = _repo.GetAllCustomers();
    var filteredCustomers = from CUST in customers
    join ST in States on CT.Tag_Id equals ST.Id                       
    where CUST.ID == customer.ID  && Expression(dynamicQuery)

2 个答案:

答案 0 :(得分:2)

通过动态表达式来实现 基本上意味着构建一个树:

(x.Foo == val0 || x.Foo == val1 || x.Foo == val2)

你可以这样做:

static Expression<Func<T, bool>> Where<T, TVal>(Expression<Func<T, TVal>> selector,
    IEnumerable<TVal> values)
{
    Expression result = null;
    foreach (var val in values)
    {
        var match = Expression.Equal(
            selector.Body,
            Expression.Constant(val, typeof(TVal)));

        result = result == null ? match : Expression.OrElse(result, match);
    }
    if (result == null) return x => true; // always match if no inputs

    return Expression.Lambda<Func<T, bool>>(result, selector.Parameters);
}

示例用法:

string[] names = { "a", "c" };
var predicate = Where<Customer, string>(c => c.Name, names);

然后,您可以在predicate扩展方法中使用此IQueryable<T>.Where

要结合您的情况,首先执行常规 LINQ:

var customers = _repo.GetAllCustomers();
var filteredCustomers = from CUST in customers
join ST in States on CT.Tag_Id equals ST.Id                       
where CUST.ID == customer.ID;

现在作为一个单独的步骤应用额外的过滤器:

customers = customers.Where(predicate);

这样做是接受c => c.Name形式的输入 lambda,然后为每个c.Name重用c.Name == {val} 正文 ,并重用c 参数作为我们正在创建的lambda的参数。 values中的每个值都成为一个类型常量。 Expression.Equal为我们提供了==测试。 OrElse||,注意如果resultnull,则这是第一个项,因此我们只使用匹配表达式本身

答案 1 :(得分:1)

您可以添加其他加入

var customers = _repo.GetAllCustomers();

var filteredCustomers = from CUST in customers
    join ST in States on CT.Tag_Id equals ST.Id  
    join SA in statesArray on ST.Name equals SA // No need dynamic expression now          
where CUST.ID == customer.ID 

//Do something with customers