如何将谓词表达式分解为查询?
我有以下类Person
,带有自定义Where
方法:
public class Person { public string Name { get; set; } public int Age { get; set; } public string Where(Expression<Func> predicate) { return String.Empty; } }
如何以可枚举的方式检索Expression
参数名称和值?
Person p = new Person(); p.Where(i => i.Name == "Shlomi" && i.Age == 26);
用于根据表达式的名称和值构建带有参数的字符串查询。
// Eventually I will convert the above into the following: string Query = "select * from person where name = @Name AND Age = @Age"; SqlParameter[] param = new SqlParameter[] { new SqlParameter("@Name","Shlomi"), new SqlParameter("@Age","26") };
我当然认为你应该遵循StriplingWarrior的建议并使用LINQ to Entities或LINQ to SQL,但为了重新发明轮子(糟糕的是),我将建立我的先前答案 。
// Start with a method that takes a predicate and retrieves the property names static IEnumerable GetColumnNames(Expression> predicate) { // Use Expression.Body to gather the necessary details var members = GetMemberExpressions(predicate.Body); if (!members.Any()) { throw new ArgumentException( "Not reducible to a Member Access", "predicate"); } return members.Select(m => m.Member.Name); }
现在,您需要遍历表达式树,访问每个候选表达式,并确定它是否包含MemberExpression
。 下面的GetMemberExpressions
方法将遍历表达式树并检索在以下MemberExpression
找到的每个MemberExpression
:
static IEnumerable GetMemberExpressions(Expression body) { // A Queue preserves left to right reading order of expressions in the tree var candidates = new Queue(new[] { body }); while (candidates.Count > 0) { var expr = candidates.Dequeue(); if (expr is MemberExpression) { yield return ((MemberExpression)expr); } else if (expr is UnaryExpression) { candidates.Enqueue(((UnaryExpression)expr).Operand); } else if (expr is BinaryExpression) { var binary = expr as BinaryExpression; candidates.Enqueue(binary.Left); candidates.Enqueue(binary.Right); } else if (expr is MethodCallExpression) { var method = expr as MethodCallExpression; foreach (var argument in method.Arguments) { candidates.Enqueue(argument); } } else if (expr is LambdaExpression) { candidates.Enqueue(((LambdaExpression)expr).Body); } } }
问题是Expression实际上是一棵树。
例如,您有以下谓词:
Expression> expr = x => x.Name == "Shlomi" && x.Age == 26;
如果检查expr,你会看到它的主体有“AndAlso” NodeType
,它还有两个操作数属性 – Left
和Right
各自指向另一个具有“Equal” NodeType
Expression
对象,而NodeType
又有两个属性Left
和Right
指向MemberAccess
和Constant
类型的Expression
。
虽然您可以处理该树并提取所需的所有信息,但您最终将实现自己的LINQ2SQL提供程序,例如重新发明轮子。 如果您有这种感觉,我希望我提供了足够的信息来开始挖掘……
你想要做的事情非常复杂,并且有完整的框架可以做到这一点,所以你不必自己编写逻辑。 看一下LINQ to Entities和LINQ to SQL,例如