基于数组生成动态LINQ表达式
Generate dynamic LINQ expression based on array
我正在使用 LINQ 表达式查询客户并按州名过滤他们。我有以下查询,在我的 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
}
我想动态创建以下表达式:
(ST.Name == statesArray[0] ||ST.Name ==statesArray[1] ||
ST.Name== statesArray[2]||ST.Name =statesArray[3])
例如,创建如下所示的动态查询
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)
您可以添加另一个加入
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
要做到这一点通过动态表达式基本上意味着构建一棵树:
(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);
然后您可以在 IQueryable<T>.Where
扩展方法中使用此 predicate
。
要结合您的情况,首先执行您的常规 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);
它所做的是接受 input 形式的 lambda c => c.Name
,然后重用 c.Name
body 对于每个 c.Name == {val}
,并重新使用 c
参数 作为我们正在创建的 lambda 的参数。 values
中的每个值都成为类型常量。 Expression.Equal
给了我们 ==
测试。 OrElse
是||
,注意如果result
是null
,这是第一个项,所以我们只用匹配表达式本身。
我正在使用 LINQ 表达式查询客户并按州名过滤他们。我有以下查询,在我的 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
}
我想动态创建以下表达式:
(ST.Name == statesArray[0] ||ST.Name ==statesArray[1] ||
ST.Name== statesArray[2]||ST.Name =statesArray[3])
例如,创建如下所示的动态查询
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)
您可以添加另一个加入
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
要做到这一点通过动态表达式基本上意味着构建一棵树:
(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);
然后您可以在 IQueryable<T>.Where
扩展方法中使用此 predicate
。
要结合您的情况,首先执行您的常规 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);
它所做的是接受 input 形式的 lambda c => c.Name
,然后重用 c.Name
body 对于每个 c.Name == {val}
,并重新使用 c
参数 作为我们正在创建的 lambda 的参数。 values
中的每个值都成为类型常量。 Expression.Equal
给了我们 ==
测试。 OrElse
是||
,注意如果result
是null
,这是第一个项,所以我们只用匹配表达式本身。