【发布时间】:2017-08-23 17:11:07
【问题描述】:
我有一个从客户端发送的条件列表列表。我需要获取这个列表并创建一个由 EntityFramework 执行的动态 where 子句。
每个条件都有一个运算符、一个属性和一个右侧值。
每个条件列表都需要用 AND 运算。
条件列表的每个列表都需要进行 OR 运算。
如果我们有
{
"ConditionLists":[
[
{
"LhsAttributeDefinition":{
"attribute":{
"key":"isHighBandwidth",
"value":"IsHighBandwidth"
}
},
"Operator":{
"name":"equals",
"description":"=",
"validation":"",
"inputType":"dropdown"
},
"RhsValue":"true"
},
{
"LhsAttributeDefinition":{
"attribute":{
"key":"isForMobile",
"value":"IsForMobile"
}
},
"Operator":{
"name":"equals",
"description":"=",
"validation":"",
"inputType":"dropdown"
},
"RhsValue":"true"
}
],
[
{
"LhsAttributeDefinition":{
"attribute":{
"key":"isHighBandwidth",
"value":"IsHighBandwidth"
}
},
"Operator":{
"name":"equals",
"description":"=",
"validation":"",
"inputType":"dropdown"
},
"RhsValue":"true"
},
{
"LhsAttributeDefinition":{
"attribute":{
"key":"isForTablet",
"value":"IsForTablet"
}
},
"Operator":{
"name":"equals",
"description":"=",
"validation":"",
"inputType":"dropdown"
},
"RhsValue":"true"
}
]
]
}
应该会生成.Where(x => (x.isHighBandwidth == true && x.isForMobile == true) || (x.isHighBandwidth == true && x.isForTablet == true))
这是我必须使用表达式库来完成此操作的:
MethodInfo contains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
Expression finalExpression = null;
List<ParameterExpression> paramsArray = new List<ParameterExpression>();
foreach (var conditionList in conditionLists)
{
Expression andGroup = null;
foreach (var condition in conditionList)
{
Expression expression = null;
ParameterExpression param = null;
ConstantExpression constant = null;
switch (condition.LhsAttributeDefinition.Attribute.Key)
{
case "title":
param = Expression.Parameter(typeof(string), "LearningItem.Title");
constant = Expression.Constant(condition.RhsValue, typeof(string));
expression = Expression.Call(param, contains, constant);
break;
case "isHighBandwidth":
param = Expression.Parameter(typeof(string), "IsHighBandwidth");
constant = Expression.Constant(condition.RhsValue, typeof(string));
expression = Expression.Equal(param, constant);
break;
case "isForMobile":
param = Expression.Parameter(typeof(string), "IsForMobile");
constant = Expression.Constant(condition.RhsValue, typeof(string));
expression = Expression.Equal(param, constant);
break;
case "isForTablet":
param = Expression.Parameter(typeof(string), "IsForTablet");
constant = Expression.Constant(condition.RhsValue, typeof(string));
expression = Expression.Equal(param, constant);
break;
}
paramsArray.Add(param);
if (andGroup != null)
{
Expression.And(andGroup, expression);
}
else
{
andGroup = expression;
}
}
//OR the expression tree created above
if (finalExpression != null)
{
Expression.Or(finalExpression, andGroup);
}
else
{
finalExpression = andGroup;
}
}
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { query.ElementType },
query.Expression,
Expression.Lambda<Func<Activity, bool>>(finalExpression, paramsArray.ToArray<ParameterExpression>()));
return query;
所以我的想法是,在嵌套的 for 循环中,我将 AND 查询和 OR 查询构建为一个大表达式,然后在最后创建 lambda 查询。我将一路上的参数收集到一个 paramsArray(列表)中。
我的问题是,在执行时,说'ParameterExpression of type 'System.String' cannot be used for delegate parameter of type 'INOLMS.Data.Activity'' 会爆炸。我假设这是因为到目前为止我收集的参数只是一个字符串(我的示例请求正文只是 IsHighBandwidth 为 true 的单个条件),而且我不喜欢使用字符串参数并尝试获取Activity 查询。
我在这里做错了什么?
【问题讨论】:
标签: c# asp.net lambda expression