以前有一段時間被EF LINQ中的動態表達式實現困擾,因為在實際項目中有很多的可變條件搜索,比方說,我要查詢一個人,那麼搜索條件就可能有按照用戶名搜索、按照昵稱搜索、按照年齡搜索,那麼這些條件組合在一起就會有很多種,但是我們不肯能為每一種單獨寫一段程序,所以應該把這些可能產生條件抽離出來。
網上找了很多,都不是很理想,不知道哪裡找到的代碼(具體哪裡忘了,也就懶得再找一次了),貼在這,希望對其他人也有幫助
具體代碼:
1 /* ===============================================================
2 * 創 建 者:wms
3 * 創建日期:2016/12/5 13:11:22
4 * 功能描述:動態表達式幫助類
5 * ===============================================================*/
6
7 using System;
8 using System.Linq;
9 using System.Linq.Expressions;
10
11 namespace Framework.Core.Linq
12 {
13 /// <summary>
14 /// 動態表達式幫助類
15 /// </summary>
16 public static class ExpressionHelper
17 {
18 /// <summary>
19 /// Creates a predicate that evaluates to true.
20 /// </summary>
21 public static Expression<Func<T, bool>> True<T>() { return param => true; }
22
23 /// <summary>
24 /// Creates a predicate that evaluates to false.
25 /// </summary>
26 public static Expression<Func<T, bool>> False<T>() { return param => false; }
27
28 /// <summary>
29 /// Creates a predicate expression from the specified lambda expression.
30 /// </summary>
31 public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }
32
33 /// <summary>
34 /// Combines the first predicate with the second using the logical "and".
35 /// </summary>
36 public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
37 {
38 return first.Compose(second, Expression.AndAlso);
39 }
40
41 /// <summary>
42 /// Combines the first predicate with the second using the logical "or".
43 /// </summary>
44 public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
45 {
46 return first.Compose(second, Expression.OrElse);
47 }
48
49 /// <summary>
50 /// Negates the predicate.
51 /// </summary>
52 public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
53 {
54 var negated = Expression.Not(expression.Body);
55 return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
56 }
57
58 /// <summary>
59 /// Combines the first expression with the second using the specified merge function.
60 /// </summary>
61 static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
62 {
63 // zip parameters (map from parameters of second to parameters of first)
64 var map = first.Parameters
65 .Select((f, i) => new { f, s = second.Parameters[i] })
66 .ToDictionary(p => p.s, p => p.f);
67
68 // replace parameters in the second lambda expression with the parameters in the first
69 var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
70
71 // create a merged lambda expression with parameters from the first expression
72 return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
73 }
74 }
75 }
1 using System.Collections.Generic;
2 using System.Linq.Expressions;
3
4 namespace Framework.Core.Linq
5 {
6 /// <summary>
7 /// ParameterRebinder
8 /// </summary>
9 public class ParameterRebinder : ExpressionVisitor
10 {
11 /// <summary>
12 /// The ParameterExpression map
13 /// </summary>
14 readonly Dictionary<ParameterExpression, ParameterExpression> map;
15
16 /// <summary>
17 /// Initializes a new instance of the <see cref="ParameterRebinder"/> class.
18 /// </summary>
19 /// <param name="map">The map.</param>
20 ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
21 {
22 this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
23 }
24
25 /// <summary>
26 /// Replaces the parameters.
27 /// </summary>
28 /// <param name="map">The map.</param>
29 /// <param name="exp">The exp.</param>
30 /// <returns>Expression</returns>
31 public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
32 {
33 return new ParameterRebinder(map).Visit(exp);
34 }
35
36 /// <summary>
37 /// Visits the parameter.
38 /// </summary>
39 /// <param name="p">The p.</param>
40 /// <returns>Expression</returns>
41 protected override Expression VisitParameter(ParameterExpression p)
42 {
43 ParameterExpression replacement;
44
45 if (map.TryGetValue(p, out replacement))
46 {
47 p = replacement;
48 }
49
50 return base.VisitParameter(p);
51 }
52 }
53 }
假如要查詢用戶信息,查詢條件有用戶名、年齡、昵稱
Action代碼:
1 public ActionResult Index(TestUser user)
2 {
3 Expression<Func<TestUser, bool>> predicate = Framework.Core.Linq.ExpressionHelper.True<TestUser>();
4 if (!string.IsNullOrEmpty(user.UserName))
5 {
6 predicate = predicate.And(m => m.UserName.Contains(user.UserName));
7 }
8 if (user.Age != null)
9 {
10 predicate = predicate.And(m => m.Age == user.Age);
11 }
12 if (!string.IsNullOrEmpty(user.NickName))
13 {
14 predicate = predicate.And(m => m.NickName.Contains(user.NickName));
15 }
16 TestContext dbContext = new TestContext();
17
18 var list = dbContext.TestUser.Where(predicate).ToList();
19
20 return View(list);
21 }
這樣就簡單干淨多了,爽