由於項目中經常要用到類似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);
- }
- }
經測試解決問題