linq中的表达式是对Func和Action形式的委托做了一层封装,在内存中以表达式数形式存储,这种存储方式数据结构明了,有利于进行Linq to XXX查询(如很容易将linq转成sql)。还有一点linq查询默认都是延迟加载的,只有使用结果时才执行真正的查询操作(如 在执行first,last,single,count,ToList,toXXX时才进行真正的查询),这种设计将查询的方式和查询的执行进行了解耦,使得我们可以将查询方法分成多个步骤来创建,linq表达式的保存这些查询方法(就是封装的委托),在我们需要使用查询结果时,通过一个完整的方法(linq表达式组合在一起)去查询,减少了对集合的查询次数,这种特性对数据库查询很有利。
在某些场合,需要动态的编译表达式,代码如下
/// <summary>
/// 动态linq组合
/// </summary>
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.Or(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.And(expr1.Body, invokedExpr), expr1.Parameters);
}
}
调用方法
Expression<Func<Account, bool>> ExpWhere = PredicateBuilder.True<Account>();
//if (id != -1)
// ExpWhere = ExpWhere.And(q => q.ID.Equals(id));
if (Levelid != -1)
ExpWhere = ExpWhere.And(q => q.UserLevelID.Equals(Levelid));
var Accounts = db.Accounts.Where(t => t.Status.Equals(0)).Where(ExpWhere.Compile()).OrderBy(t => t.ID).Select(t => new SelectListItem
{
Text = t.TrueName,
Value = t.ID.ToString(),
}).AsQueryable();
return Accounts;