由于项目中经常要用到类似db.students.where多条件查询,因此需要拼接查询条件。
网上搜索大部分出自 Dynamically Composing Expression Predicates
code如下
- using System;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Collections.Generic;
- public static class PredicateBuilder
- {
- public static Expression<Func<T, bool>> True<T> () { return f => true; }
- public static Expression<Func<T, bool>> False<T> () { return f => false; }
- public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
- Expression<Func<T, bool>> expr2)
- {
- var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
- return Expression.Lambda<Func<T, bool>>
- (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
- }
- public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
- Expression<Func<T, bool>> expr2)
- {
- var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
- return Expression.Lambda<Func<T, bool>>
- (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
- }
- }
使用代码如下:
- var predicate = PredicateBuilder.True<Gift>();
- predicate = predicate.And(w => w.DataState == DataStateEnum.正常);
- List<Gift> list = db.Gifts.Where(predicate);
但出现异常:LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”
网上继续搜索,其中一种如下:
List<Gift> list = db.Gifts.Where(predicate.Compile());作者文中提到“他在Linq to sql 上运行正常”,没有验证,
这样确实可以正常工作,但predicate.Compile()后就变成了Func<T, bool>类型,
Entity Framework - Func引起的数据库全表查询
使用 Entity Framework 最要小心的性能杀手就是 —— 不正确的查询代码造成的数据库全表查询。
“将Func类型的变量作为参数传给Where方法进行LINQ查询时,Enitity Framework会产生全表查询,将整个数据库表中的数据加载到内存,然后在内存中根据Where中的条件进一步查询。” 经SQL Server Profiler监测确实如此。
继续找解决办法,找到个Combining two expressions (Expression<func>)
有人回答:
- //Starting from .net 4.0. There is the ExpressionVistor class which allows you to build expressions that are EF safe.
- public static Expression<Func<T, bool>> AndAlso<T>(
- this Expression<Func<T, bool>> expr1,
- Expression<Func<T, bool>> expr2)
- {
- var parameter = Expression.Parameter(typeof (T));
- var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
- var left = leftVisitor.Visit(expr1.Body);
- var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
- var right = rightVisitor.Visit(expr2.Body);
- return Expression.Lambda<Func<T, bool>>(
- Expression.AndAlso(left, right), parameter);
- }
- private class ReplaceExpressionVisitor
- : ExpressionVisitor
- {
- private readonly Expression _oldValue;
- private readonly Expression _newValue;
- public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
- {
- _oldValue = oldValue;
- _newValue = newValue;
- }
- public override Expression Visit(Expression node)
- {
- if (node == _oldValue)
- return _newValue;
- return base.Visit(node);
- }
- }
经测试解决问题