在使用Linq查詢的時候,特別是如果你在使用Entiry Framwork,有時會遇到動態查詢的情況(客戶的查詢條件是不固定的拼接查詢)。
我們能想到的第一方案應該是拼接SQL,的確這樣是可以達到我們的目的的。但這樣又會破壞程序的一至性,本來使用Entiry Framwork的目標就是用面向對象的方式操縱數據庫,這樣我們又要開始寫SQL語句了。
其實我一開始也是這樣做的直到有一天我們部門的美女程序員給我介紹LinqKit,我才開始用PredicateBuilder來拼接Predicate委托。
PredicateBuilder是LinqKit庫的一部分,下面是PredicateBuilder源代碼:
using System; using System.Linq; using System.Linq.Expressions; namespace LinqUtil { 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); } } }
這里主要是介紹PredicateBuilder的使用,如想了解PredicateBuilder具體是怎么實現的可以看看這篇文章:傳送門
引入PredicateBuilder依賴
- 用VS的NuGet安裝LinqKit
- 直接引用上面的源碼
創建PredicateBuilder對象
var where = PredicateBuilder.True<TrendStatics>();
可以理解為創建一個初始化為True的Predicate。
注意:如果你是要創建一個OR組成的Predicate就不能把它初始化為True因為這樣這個表達試永遠為True了。
var where = PredicateBuilder.False<TrendStatics>();
可以理解為創建一個初始化為False的Predicate。
注意:如果你是要創建一個AND組成的Predicate就不能把它初始化為False因為這樣這個表達試永遠為False了。
PredicateBuilder對象拼接
現在你可以對Predicate進行各種拼接了
- 全And:
-
var where = PredicateBuilder.True<int>(); where = where.And(x => x >= 50); where = where.And(x => x <= 70); var res = list.Where(where.Compile());
- 全Or:
-
var list = Enumerable.Range(1, 100); var where = PredicateBuilder.False<int>(); where = where.Or(x => x == 50); where = where.Or(x => x == 70); var res = list.Where(where.Compile());
- 各種組合:
-
var list = Enumerable.Range(1, 100); var where = PredicateBuilder.True<int>(); where = where.And(x => x >= 50); where = where.And(x => x <= 70); var subwhere = PredicateBuilder.False<int>(); subwhere = subwhere.Or(x => x == 60); subwhere = subwhere.Or(x => x == 61); where = where.And(subwhere); var res = list.Where(where.Compile());
PredicateBuilder對象使用
- 針對集合Linq查詢
你可以這樣用:
var res = list.Where(where.Compile());
你還可以這樣用:
var res = list.AsQueryable().Where(where);
- 針對Entity Framework:
var res = table.Where(where.Expand());