【发布时间】:2013-11-30 05:44:54
【问题描述】:
我最近遇到了为 Kendo UI 网格控件实现服务器端过滤的需求。由于 linq to entity lambda 表达式中的比较运算符在编译时是未知的,因此有必要动态构建表达式。我以前从来没有需要这样做,但我做了足够多的挖掘来弄清楚如何从表达式树构建简单的 lambda 表达式。例如,我为一个简单的过滤器(例如people.Where(person => person.LastName == "Doe"))构建表达式,如下所示:
ParameterExpression filterParam = Expression.Parameter(typeof(Person), "person");
MemberExpression left = Expression.Property(filterParam, "LastName");
ConstantExpression right = Expression.Constant("Doe", typeof(string));
BinaryExpression predicate = Expression.Equal(left, right);
Expression<Func<Person, bool>> lambda = Expression.Lambda<Func<Person, bool>(predicate, filterParam);
IQueryable<Person> filtered = people.Where(lambda);
好的,那么问题来了。我遇到了需要做与上面类似的事情,除了按全名而不是姓氏过滤。我的数据库中没有用于全名的字段——只是单独的名字和姓氏字段,所以我不能为此引用单个属性。我需要连接表达式中的两个属性,以便生成的 lambda 看起来像:
people.Where(person => (person.firstName + person.LastName) == "JohnDoe")
我还没有找到一个示例来展示如何从表达式树动态构建一个像这样的 lambda。我假设它一定是可能的——它看起来不像那种疯狂的场景,是吗?
编辑:我也有兴趣知道怎么做:
people.Where(person => (person.FirstName + " " + person.LastName) == "John Doe")
Edit2:解决这个问题的方法是对国王的回答进行非常简单的改变:
ParameterExpression filterParam = Expression.Parameter(typeof(Person), "person");
MemberExpression first = Expression.Property(filterParam, "FirstName");
MemberExpression last = Expression.Property(filterParam, "LastName");
Type strType = typeof(string);
MethodCallExpression concat = Expression.Call(typeof(string).GetMethod("Concat", new [] { strType, strType, strType }),
first, Expression.Constant(" ", strType), last);
ConstantExpression right = Expression.Constant("John Doe", strType);
BinaryExpression predicate = Expression.Equals(concat, right);
Expression<Func<Person, bool>> lambda = Expression.Lambda<Func<Person, bool>>(predicate, filterParam);
IQueryable<Person> filtered = people.Where(lambda);
【问题讨论】:
-
了解如何构建给定表达式的一个好方法是使用 LinqPad(免费)。只需将表达式创建为变量并将其转储 (Expression
> e = p => ...; p.Dump() -
感谢您的提示。我得试试看。
标签: c# lambda linq-to-entities