一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件

简单方式这样操作就可以了

  1. public IQueryable<FileImport> DynamicChainedSyntax
  2. (IQueryable<FileImport> files, bool pastOnly)
  3. {
  4. var query = files.Where(file => file.ImportDate >
  5. DateTime.Now.AddDays(-7));
  6. if (pastOnly)
  7. query = query.Where(file => file.ImportDate <
  8. DateTime.Today);
  9. return query;
  10. }

这里的多个where条件是AND关系,如果是OR的关系,可将多次查询的结果进行union

当然大多数的时候,我们是希望能够动态构建查询条件的,你可以针对任何字段进行任何操作符形式的查询,不同查询条件之间的关系也是可以动态定义的。

这时候表达式树就派上用场了,关于表达式树的基础知识已经在上一篇中提到了。

这里主要说如何构建linq中Where查询条件,其实只是熟悉表达式树的其他提供的方法,非常简单。

  1. public Func<TSource, bool> SimpleComparison<TSource>
  2. string property, object value)
  3. {
  4. var type = typeof (TSource);
  5. var pe = Expression.Parameter(type, "p");
  6. var propertyReference = Expression.Property(pe, property);
  7. var constantReference = Expression.Constant(value);
  8. return Expression.Lambda<Func<TSource, bool>>
  9. (Expression.Equal(propertyReference, constantReference),
  10. new[] { pe }).Compile();
  11. }

呵呵,话到这里,看看我的小DEMO

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace ConsoleApplication1
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. //(a,b)=>(a+b)
  14. //参数的构建  (定义参数的名字和参数的类型)
  15. ParameterExpression exp1 = Expression.Parameter(typeof(int), "a");
  16. ParameterExpression exp2 = Expression.Parameter(typeof(int), "b");
  17. //表达式主体的构建
  18. BinaryExpression exp = Expression.Add(exp1, exp2);
  19. //表达式树的构建(如下定义,表达式的类型为Lambda
  20. //lambda表达式的类型为Func<int, int, int>)
  21. var lambda = Expression.Lambda<Func<int, int, int>>(exp, exp1, exp2);
  22. //p=>p.Name 可以动态构建OrderBy
  23. ParameterExpression exp3 = Expression.Parameter(typeof(Person), "p");
  24. var property = Expression.Property(exp3, "Name");
  25. var lambda2 = Expression.Lambda<Func<Person, string>>(property, exp3);
  26. //p=>p.Name == "daisy"
  27. List<Person> persons = new List<Person>()
  28. { new Person(){ Name = "daisy", age = 10 },
  29. new Person(){ Name = "daisy", age = 12 },
  30. new Person(){Name="dom", age=12},
  31. new Person(){Name="caren", age=10}};
  32. var compareExp = simpleCompare<Person>("Name", "daisy");
  33. var daisys = persons.Where(compareExp).ToList();
  34. foreach (var item in daisys)
  35. {
  36. Console.WriteLine("Name:  "+item.Name+"    Age:  "+item.age);
  37. }
  38. Console.ReadKey();
  39. }
  40. public static Func<TSource, bool> simpleCompare<TSource>(string property, object value)
  41. {
  42. var type = typeof(TSource);
  43. var pe = Expression.Parameter(type, "p");
  44. var propertyReference = Expression.Property(pe, property);
  45. var constantReference = Expression.Constant(value);
  46. //compile 是表达式的一个接口,生成该lambda表达式树对的委托
  47. return Expression.Lambda<Func<TSource, bool>>(Expression.Equal(propertyReference, constantReference), pe).Compile();
  48. }
  49. }
  50. public class Person
  51. {
  52. public string Name { get; set; }
  53. public int age { get; set; }
  54. }
  55. }

再来看看查询结果:

嗯,理解起来还是非常简单的,就是构建表达式树,返回我们需要的委托类型!

接下来猛料哦

动态构建表达式树,最佳实践版,很实用!

  1. public class FilterCollection : Collection<IList<Filter>>
  2. {
  3. public FilterCollection()
  4. : base()
  5. { }
  6. }
  7. public class Filter
  8. {
  9. public string PropertyName { get; set; }
  10. public Op Operation { get; set; }
  11. public object Value { get; set; }
  12. }
  13. public enum Op
  14. {
  15. Equals,
  16. GreaterThan,
  17. LessThan,
  18. GreaterThanOrEqual,
  19. LessThanOrEqual,
  20. Contains,
  21. StartsWith,
  22. EndsWith
  23. }

通过上面的类可以动态构建复杂的查询条件,下面具体调用的类哦

  1. using Infrastructure.Model;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace Infrastructure.Operation
  10. {
  11. public static class LambdaExpressionBuilder
  12. {
  13. private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");
  14. private static MethodInfo startsWithMethod =
  15. typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
  16. private static MethodInfo endsWithMethod =
  17. typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
  18. private static Expression GetExpression(ParameterExpression param, Filter filter)
  19. {
  20. MemberExpression member = Expression.Property(param, filter.PropertyName);
  21. Expression handledMember = member;
  22. ConstantExpression constant = Expression.Constant(filter.Value);
  23. if (member.Member.MemberType == MemberTypes.Property)
  24. {
  25. Type propertyType = ((PropertyInfo)member.Member).PropertyType;
  26. if (propertyType == typeof(string))
  27. {
  28. handledMember = Expression.Call(member, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
  29. }
  30. if (propertyType == typeof(DateTime?))
  31. {
  32. handledMember = Expression.Property(member, typeof(DateTime?).GetProperty("Value"));
  33. }
  34. }
  35. switch (filter.Operation)
  36. {
  37. case Op.Equals:
  38. return Expression.Equal(handledMember, constant);
  39. case Op.GreaterThan:
  40. return Expression.GreaterThan(handledMember, constant);
  41. case Op.GreaterThanOrEqual:
  42. return Expression.GreaterThanOrEqual(handledMember, constant);
  43. case Op.LessThan:
  44. return Expression.LessThan(handledMember, constant);
  45. case Op.LessThanOrEqual:
  46. return Expression.LessThanOrEqual(handledMember, constant);
  47. case Op.Contains:
  48. return Expression.Call(handledMember, containsMethod, constant);
  49. case Op.StartsWith:
  50. return Expression.Call(handledMember, startsWithMethod, constant);
  51. case Op.EndsWith:
  52. return Expression.Call(handledMember, endsWithMethod, constant);
  53. }
  54. return null;
  55. }
  56. private static BinaryExpression GetORExpression(ParameterExpression param, Filter filter1, Filter filter2)
  57. {
  58. Expression bin1 = GetExpression(param, filter1);
  59. Expression bin2 = GetExpression(param, filter2);
  60. return Expression.Or(bin1, bin2);
  61. }
  62. private static Expression GetExpression(ParameterExpression param, IList<Filter> orFilters)
  63. {
  64. if (orFilters.Count == 0)
  65. return null;
  66. Expression exp = null;
  67. if (orFilters.Count == 1)
  68. {
  69. exp = GetExpression(param, orFilters[0]);
  70. }
  71. else if (orFilters.Count == 2)
  72. {
  73. exp = GetORExpression(param, orFilters[0], orFilters[1]);
  74. }
  75. else
  76. {
  77. while (orFilters.Count > 0)
  78. {
  79. var f1 = orFilters[0];
  80. var f2 = orFilters[1];
  81. if (exp == null)
  82. {
  83. exp = GetORExpression(param, orFilters[0], orFilters[1]);
  84. }
  85. else
  86. {
  87. exp = Expression.Or(exp, GetORExpression(param, orFilters[0], orFilters[1]));
  88. }
  89. orFilters.Remove(f1);
  90. orFilters.Remove(f2);
  91. if (orFilters.Count == 1)
  92. {
  93. exp = Expression.Or(exp, GetExpression(param, orFilters[0]));
  94. orFilters.RemoveAt(0);
  95. }
  96. }
  97. }
  98. return exp;
  99. }
  100. public static Expression<Func<T, bool>> GetExpression<T>(FilterCollection filters)
  101. {
  102. if (filters == null || filters.Count == 0)
  103. return null;
  104. ParameterExpression param = Expression.Parameter(typeof(T), "t");
  105. Expression exp = null;
  106. if (filters.Count == 1)
  107. {
  108. exp = GetExpression(param, filters[0]);
  109. }
  110. else if (filters.Count == 2)
  111. {
  112. exp = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));
  113. }
  114. else
  115. {
  116. while (filters.Count > 0)
  117. {
  118. var f1 = filters[0];
  119. var f2 = filters[1];
  120. var f1Andf2 = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));
  121. if (exp == null)
  122. {
  123. exp = f1Andf2;
  124. }
  125. else
  126. {
  127. exp = Expression.AndAlso(exp, f1Andf2);
  128. }
  129. filters.Remove(f1);
  130. filters.Remove(f2);
  131. if (filters.Count == 1)
  132. {
  133. exp = Expression.AndAlso(exp, GetExpression(param, filters[0]));
  134. filters.RemoveAt(0);
  135. }
  136. }
  137. }
  138. return Expression.Lambda<Func<T, bool>>(exp, param);
  139. }
  140. }
  141. }

再来一个OrderBy动态构建

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using System.Text;
  7. namespace Jurassic.Sooil.Com
  8. {
  9. public static class OrderExpression
  10. {
  11. public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
  12. {
  13. return ApplyOrder<T>(source, property, "OrderBy");
  14. }
  15. public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
  16. {
  17. return ApplyOrder<T>(source, property, "OrderByDescending");
  18. }
  19. public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
  20. {
  21. return ApplyOrder<T>(source, property, "ThenBy");
  22. }
  23. public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
  24. {
  25. return ApplyOrder<T>(source, property, "ThenByDescending");
  26. }
  27. static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
  28. {
  29. string[] props = property.Split('.');
  30. Type type = typeof(T);
  31. ParameterExpression arg = Expression.Parameter(type, "x");
  32. Expression expr = arg;
  33. foreach (string prop in props)
  34. {
  35. // use reflection (not ComponentModel) to mirror LINQ
  36. PropertyInfo pi = type.GetProperty(prop);
  37. expr = Expression.Property(expr, pi);
  38. type = pi.PropertyType;
  39. }
  40. Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
  41. LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
  42. object result = typeof(Queryable).GetMethods().Single(
  43. method => method.Name == methodName
  44. && method.IsGenericMethodDefinition
  45. && method.GetGenericArguments().Length == 2
  46. && method.GetParameters().Length == 2)
  47. .MakeGenericMethod(typeof(T), type)
  48. .Invoke(null, new object[] { source, lambda });
  49. return (IOrderedQueryable<T>)result;
  50. }
  51. }
  52. }

至此动态构建LINQ查询结束!花了上班时间一上午,还是相当值得的,不过被项目经理知道了得哭死!

不管如何,学到手的才是自己的!

c#——表达式树在LINQ动态查询的更多相关文章

  1. 表达式树在LINQ动态查询

    动态构建表达式树,最佳实践版,很实用! public class FilterCollection : Collection<IList<Filter>> { public F ...

  2. Linq动态查询与模糊查询 ---转

    Linq动态查询与模糊查询(带源码示例) 继LINQ动态组合查询PredicateExtensions讲解 ----- 在用上面的方法时遇到了些问题 解决 LINQ to Entities 不支持 L ...

  3. Linq动态查询简易解决之道(原创)

    因为项目需要使用Linq来查询数据,但是在多条件查询时,需要使用一大堆if(...!=string.empty)等判断条件感觉不是很优雅.网上搜索以下,大概找到了两种办法,一种是老外写的一个类,感觉用 ...

  4. Linq 动态查询排序

    Linq的排序一般是这样写的: query.OrderBy(x => x.Tel).Skip().Take(); 实际使用中排序字段可能是通过字符类型的参数来设置的,于是想这样实现: query ...

  5. 洛谷3834 hdu2665主席树模板,动态查询区间第k小

    题目链接:https://www.luogu.com.cn/problem/P3834 对于区间查询第k小的问题,在区间数量达到5e5的时候是难以用朴素数据结构实现的,这时候主席树就应运而生了,主席树 ...

  6. Linq动态查询

    public class ExpressionCall { List<Customer> customers = new List<Customer>() { new Cust ...

  7. linq字符串搜索条件,排序条件-linq动态查询语句 Dynamic LINQ

    在做搜索和排序的时候,往往是前台传过来的字符串做条件,参数的数量还不定,这就需要用拼sql语句一样拼linq语句.而linq语句又是强类型的,不能用字符串拼出来. 现在好了,有个开源的linq扩展方法 ...

  8. LINQ动态查询类--[DynamicLinqExpressions]

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.L ...

  9. 转载:C#特性-表达式树

    原文地址:http://www.cnblogs.com/tianfan/ 表达式树基础 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家看到它其实并不像想象中那么难.您只要有普通 ...

随机推荐

  1. 使用Loadrunner进行文件的上传和下载

    最近使用loadrunner中需要录制文件的上传和下载,上传功能模块利用录制可以直接实现,下载无法实现,在网上找到了一段代码,自己动手试验了下,发现没有用 辛苦找到的,还是记录下吧 (1)LoadRu ...

  2. 【Python 数据分析】pandas数据导入

    导入CSV文件数据 环境 C:\Users\Thinkpad\Desktop\Data\信息表.csv 语法 pd.read_csv(filename):从CSV文件导入数据 实现代码 import ...

  3. HTML-HTML5+CSS3权威指南阅读(五、设备像素和CSS像素的概念)

    在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工作的,比如<html>元素,也包括窗口和屏幕 这篇文章是关于桌面浏览器的,其唯一目的就是为移动浏览器中相似 ...

  4. C# 视频监控系列:学习地址汇总

    原文地址:http://www.cnblogs.com/over140/archive/2009/04/07/1429308.html 前言 对于视频监控系统大家应该是不陌生的,实施的路况信息.地铁. ...

  5. 常用 cdn

    http://www.bootcdn.cn/ jquery <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.j ...

  6. [gj]耶稣和撒旦的关系

    转: https://zhidao.baidu.com/question/7461904.html 人生充满试探,无论你居住在乡间或城市,都尝会受到试探,耶稣在世上的日子,也受到试探,让我们看看两处经 ...

  7. linux内存排查工具valgrind

    官网:http://valgrind.org/info/about.html 百科介绍:http://baike.baidu.com/link?url=ZdXzff0omzoPpE_yZUlNW9lJ ...

  8. 使用response.setHeader("Content-Disposition","attachment;filename="+fName)下载文件,中文文件名无法显示的问题

    今天遇到这么一个情况,在Action代码中进行文件下载: ActionForm得到file_id,通过file_id进行数据库查询得到file_name以及服务器硬盘上的file_uri,其中file ...

  9. PL/SQL Developer导入、导出表结构和表数据

    在表的所有者不能改变的情况下,可以使用导入导出表结构和表数据的方法,将表移动到你想要的所有者下(注:特别是建立表的时候如果以sysdba的身份登录的话,所有表的所有者都为sys,此时会对你用c#访问数 ...

  10. 1. Retrofit2 -- Getting Started and Create an Android Client

    1. Retrofit2 -- Getting Started and Create an Android Client Retrofit tutorial 什么是 Retrofit 如何申明请求 准 ...