通过迭代对象属性生成动态 LINQ 表达式
Generate Dynamic LINQ Expression By Iterating object properties
我正在尝试遍历对象中的所有属性,包括嵌套对象和集合中的对象,以生成 LINQ 表达式。我的类的结构如下:
public class Rule
{
public string label { get; set; }
public string field { get; set; }
public string @operator { get; set; }
public string type { get; set; }
public string value { get; set; }
public string condition { get; set; }
public List<Rule> rules { get; set; }
}
public class QueryBuilder
{
public string condition { get; set; }
public List<Rule> rules { get; set; }
}
下面是上述实体映射的示例JSON
{
"condition": "and",
"rules": [
{
"condition": "or",
"rules": [
{
"label": "PaymentMode",
"field": "PaymentMode",
"operator": "equal",
"type": "string",
"value": "Cash"
},
{
"label": "TransactionType",
"field": "TransactionType",
"operator": "equal",
"type": "string",
"value": "expensive"
}
]
},
{
"condition": "or",
"rules": [
{
"label": "Date",
"field": "Date",
"operator": "equal",
"type": "date",
"value": "4/15/21"
},
{
"label": "Date",
"field": "Date",
"operator": "equal",
"type": "date",
"value": "4/15/21"
}
]
}
]
}
上面的 json 将在一个层次结构中。用户可以 select 任意数量的 AND 或 OR 条件。需要在递归循环中制作波纹管表达式
var constant = Expression.Constant("Jhon");
var property = Expression.Property(paramExpr,"FirstName");
expression = Expression.Equal(property, constant);
constant = Expression.Constant("Ram");
property = Expression.Property(paramExpr, "LastName");
var expression2 = Expression.Equal(property, constant);
expression = Expression.Or(expression, expression2);
如何使用上述结构进行递归循环。
应该这样做:
public Expression BuildExpression(ParameterExpression paramExpr, Rule rule)
{
if (rule.condition != null)
{
if (rule.condition != "or" && rule.condition != "and")
throw new Exception($"Condition [{rule.condition}] is invalid.");
if (rule.rules == null || rule.rules.Count < 2)
throw new Exception($"Cannot create [{rule.condition}] expression.");
IList<Expression> expressions = rule.rules
.Select(rule => BuildExpression(paramExpr, rule))
.ToList();
if (rule.condition == "or")
return JoinExpressions(expressions, (left, right) => Expression.OrElse(left, right));
else
return JoinExpressions(expressions, (left, right) => Expression.AndAlso(left, right));
}
else
{
Expression constant = Expression.Constant(rule.value);
Expression property = Expression.Property(paramExpr, rule.field);
// added to allow any value to be included.
if (rule.value == "ANY")
{
Type type = GetType(rule.type);
if (!type.IsPrimitive)
{
constant = Expression.Constant(null, type);
switch (rule.@operator)
{
case "equal": return Expression.NotEqual(property, constant);
case "notequal": return Expression.Equal(property, constant);
default:
throw new Exception($"Operator [{rule.@operator}] is invalid for ANY filter. Use only equal or notequal.");
}
}
constant = property;
}
switch (rule.@operator)
{
case "equal": return Expression.Equal(property, constant);
case "notequal": return Expression.NotEqual(property, constant);
case "greaterthan": return Expression.GreaterThan(property, constant);
case "greaterthanorequal": return Expression.GreaterThanOrEqual(property, constant);
case "lessthan": return Expression.LessThan(property, constant);
case "lessthanorequal": return Expression.LessThanOrEqual(property, constant);
default:
throw new Exception($"Operator [{rule.@operator}] is invalid.");
}
}
}
public Expression JoinExpressions(IList<Expression> expressions, Func<Expression, Expression, Expression> join)
{
Expression andExpression = null;
foreach (Expression expression in expressions)
{
if (andExpression == null)
andExpression = expression;
else
andExpression = join(andExpression, expression);
}
return andExpression;
}
public static Type GetType(string typeName)
{
switch (typeName)
{
case "string": return typeof(string);
... add any others.
default:
throw new Exception($"Type [{typeName}] is invalid.");
}
}
我正在尝试遍历对象中的所有属性,包括嵌套对象和集合中的对象,以生成 LINQ 表达式。我的类的结构如下:
public class Rule
{
public string label { get; set; }
public string field { get; set; }
public string @operator { get; set; }
public string type { get; set; }
public string value { get; set; }
public string condition { get; set; }
public List<Rule> rules { get; set; }
}
public class QueryBuilder
{
public string condition { get; set; }
public List<Rule> rules { get; set; }
}
下面是上述实体映射的示例JSON
{
"condition": "and",
"rules": [
{
"condition": "or",
"rules": [
{
"label": "PaymentMode",
"field": "PaymentMode",
"operator": "equal",
"type": "string",
"value": "Cash"
},
{
"label": "TransactionType",
"field": "TransactionType",
"operator": "equal",
"type": "string",
"value": "expensive"
}
]
},
{
"condition": "or",
"rules": [
{
"label": "Date",
"field": "Date",
"operator": "equal",
"type": "date",
"value": "4/15/21"
},
{
"label": "Date",
"field": "Date",
"operator": "equal",
"type": "date",
"value": "4/15/21"
}
]
}
]
}
上面的 json 将在一个层次结构中。用户可以 select 任意数量的 AND 或 OR 条件。需要在递归循环中制作波纹管表达式
var constant = Expression.Constant("Jhon");
var property = Expression.Property(paramExpr,"FirstName");
expression = Expression.Equal(property, constant);
constant = Expression.Constant("Ram");
property = Expression.Property(paramExpr, "LastName");
var expression2 = Expression.Equal(property, constant);
expression = Expression.Or(expression, expression2);
如何使用上述结构进行递归循环。
应该这样做:
public Expression BuildExpression(ParameterExpression paramExpr, Rule rule)
{
if (rule.condition != null)
{
if (rule.condition != "or" && rule.condition != "and")
throw new Exception($"Condition [{rule.condition}] is invalid.");
if (rule.rules == null || rule.rules.Count < 2)
throw new Exception($"Cannot create [{rule.condition}] expression.");
IList<Expression> expressions = rule.rules
.Select(rule => BuildExpression(paramExpr, rule))
.ToList();
if (rule.condition == "or")
return JoinExpressions(expressions, (left, right) => Expression.OrElse(left, right));
else
return JoinExpressions(expressions, (left, right) => Expression.AndAlso(left, right));
}
else
{
Expression constant = Expression.Constant(rule.value);
Expression property = Expression.Property(paramExpr, rule.field);
// added to allow any value to be included.
if (rule.value == "ANY")
{
Type type = GetType(rule.type);
if (!type.IsPrimitive)
{
constant = Expression.Constant(null, type);
switch (rule.@operator)
{
case "equal": return Expression.NotEqual(property, constant);
case "notequal": return Expression.Equal(property, constant);
default:
throw new Exception($"Operator [{rule.@operator}] is invalid for ANY filter. Use only equal or notequal.");
}
}
constant = property;
}
switch (rule.@operator)
{
case "equal": return Expression.Equal(property, constant);
case "notequal": return Expression.NotEqual(property, constant);
case "greaterthan": return Expression.GreaterThan(property, constant);
case "greaterthanorequal": return Expression.GreaterThanOrEqual(property, constant);
case "lessthan": return Expression.LessThan(property, constant);
case "lessthanorequal": return Expression.LessThanOrEqual(property, constant);
default:
throw new Exception($"Operator [{rule.@operator}] is invalid.");
}
}
}
public Expression JoinExpressions(IList<Expression> expressions, Func<Expression, Expression, Expression> join)
{
Expression andExpression = null;
foreach (Expression expression in expressions)
{
if (andExpression == null)
andExpression = expression;
else
andExpression = join(andExpression, expression);
}
return andExpression;
}
public static Type GetType(string typeName)
{
switch (typeName)
{
case "string": return typeof(string);
... add any others.
default:
throw new Exception($"Type [{typeName}] is invalid.");
}
}