表达式树Expression
Expression表达式树动态查询
在进行数据列表的查询中,我们通常会使用两种方式进行查询:
- linq查询
- 数据库sql语句查询
这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少。使用linq,可以将所有的查询条件的属性传到后台,再根据该属性是否有值,使用where进行查询;使用存储过程,也需要将所有查询条件的属性传到后台,
再根据该属性是否有值进行sql语句的拼接。这样做在查询条件很少的时候固然没啥影响,但是有一天做查询列表的时候,本人碰到了一个查询条件高达接近10个的情况,这样再使用上述的方法固然也可以实现,但是可能会使用多个
条件去判断,然后使用多个where查询,如果在数据库使用sql语句拼接,可能会产生很长的sql拼接查询的代码,在调试的时候还要用print去打印才能看到完整的查询条件,所以我就想,能不能写一种方法可以动态产生查询的条件
,不管列表的查询条件有十个还是几十个,我只需要将查询的属性作为一个对象传到后台,再将这个查询属性的对象丢给这个方法,让它动态产生查询的表达式,然后使用linq中的where去查询呢?于是我便踏上了探索Expression表
达式树的路途!下面我写出自己的代码,希望和大家能一起交流学习!
经过查询资料和研究,终于写出了以下这套代码来达到目的:
1.定义一个查询的特性类,_displayName用于指明查询条件的类的各个属性用于和数据源列表元素对象的各个属性比较的属性名称(注意:_displayName的值必须和数据源中各个属性名称相同),_operation用于指明比较的操作
类型,类的代码如下:

1 public class SearchAttribute : Attribute
2 {
3 /// <summary>
4 /// 属性名称,用于对比查询
5 /// </summary>
6 private string _displayName;
7 /// <summary>
8 /// 操作类型
9 /// </summary>
10 private OperationType _operation;
11
12 public string DisplayName
13 {
14 get { return _displayName; }
15 }
16 public OperationType Operation
17 {
18 get { return _operation; }
19 }
20
21 public SearchAttribute(string displayName, OperationType operation)
22 {
23 _displayName = displayName;
24 _operation = operation;
25 }
26
27 /// <summary>
28 /// 不是查询的条件时调用此构造函数 参数值=OperationType.None
29 /// </summary>
30 /// <param name="operation"></param>
31 public SearchAttribute(OperationType operation)
32 {
33 _operation = operation;
34 }
35 }

2.定义一个比较的操作类型的枚举类型

1 /// <summary>
2 /// 查询操作类型
3 /// </summary>
4 public enum OperationType
5 {
6 /// <summary>
7 /// 不进行查询
8 /// </summary>
9 None,
10 /// <summary>
11 /// 比较该查询属性的值是否与元数据数据的值相等 即sql中=
12 /// </summary>
13 Equal,
14 /// <summary>
15 /// 比较元数据数据的值是否包含该查询属性的值 即sql中like
16 /// </summary>
17 Like,
18 /// <summary>
19 /// 大于
20 /// </summary>
21 GreaterThan,
22 /// <summary>
23 /// 小于
24 /// </summary>
25 LessThan,
26 /// <summary>
27 /// >=
28 /// </summary>
29 GreaterThanOrEqual,
30 /// <summary>
31 /// <=
32 /// </summary>
33 LessThanOrEqual
34 }

3.核心代码来了,哈哈

1 public static class Query
2 {
3 public static IQueryable<TSource> Search<TSource,T>(this IQueryable<TSource> queryList, T searchOptions)
4 {
5 return queryList.Where(Search<TSource,T>(searchOptions));
6 }
7
8 private static Expression<Func<TSource, bool>> Search<TSource,T>(T searchOptionEntity)
9 {
10 var dataSouceType = typeof(TSource); //数据源列表元素对象的类型
11 var dataSource = new
12 {
13 Type = dataSouceType, //数据源列表元素对象的类型
14 Properties = dataSouceType.GetProperties(), //数据源列表元素对象的属性集合
15 };
16
17 //List<string> sourcePropertyName = sourceProperties.Select(p => p.Name).ToList();
18
19 PropertyInfo[] searchProperties = searchOptionEntity.GetType().GetProperties(); //查询选择器对象的属性集合
20
21 var pe = Expression.Parameter(dataSource.Type, "p"); //创建一个 ParameterExpression 节点,该节点可用于标识表达式树中的参数或变量
22 var expression = Expression.Equal(Expression.Constant(true), Expression.Constant(true));
23
24 //遍历查询选择器对象的属性集合
25 foreach (var property in searchProperties)
26 {
27 var propertySearchAttribute = property.GetCustomAttributes(true)[0] as SearchAttribute; //获取查询选择器属性的自定义特性对象
28 var propertySearchVlaue = property.GetValue(searchOptionEntity, null); //获取查询选择器属性的值
29 var propertySearchAttributeName = propertySearchAttribute.DisplayName; //获取查询选择器属性的自定义特性对象的对比查询的字段名称
30
31 //查询选择器中的该属性的自定义的对比查询的字段名称 in 数据源列表对象的属性集合 && 查询选择器中的该属性是查询的条件 && 查询选择器该属性的值!=null或者""
32 if (Array.Exists(dataSource.Properties, p => p.Name == propertySearchAttributeName) && propertySearchAttribute.Operation!=OperationType.None && propertySearchVlaue != null && propertySearchVlaue != (object)string.Empty)
33 {
34 var propertyReference = Expression.Property(pe, propertySearchAttributeName);
35 var sourcePropertyType = dataSource.Properties.FirstOrDefault(p => p.Name == propertySearchAttributeName).PropertyType; //获取数据源列表元素对象的单个属性的属性类型
36 ConstantExpression constantReference = null;
37 Expression Expr = null;
38
39 bool isGenericType = sourcePropertyType.IsGenericType && sourcePropertyType.GetGenericTypeDefinition() == typeof(Nullable<>); //搜索sourcePropertyType是否可为空
40 if (isGenericType)
41 constantReference = Expression.Constant(Convert.ChangeType(propertySearchVlaue, Nullable.GetUnderlyingType(sourcePropertyType)), sourcePropertyType); //如果可为空类型,则将propertySearchVlaue的类型设置为可为空类型
42 else
43 constantReference = Expression.Constant(Convert.ChangeType(propertySearchVlaue, sourcePropertyType));
44
45 //根据查询选择器中该属性的查询条件进行不同的操作
46 switch (propertySearchAttribute.Operation)
47 {
48 case OperationType.Equal:
49 Expr = Expression.Equal(propertyReference, constantReference);
50 break;
51 case OperationType.GreaterThan:
52 Expr = Expression.GreaterThan(propertyReference, constantReference);
53 break;
54 case OperationType.LessThan:
55 Expr = Expression.LessThan(propertyReference, constantReference);
56 break;
57 case OperationType.GreaterThanOrEqual:
58 Expr = Expression.GreaterThanOrEqual(propertyReference, constantReference);
59 break;
60 case OperationType.LessThanOrEqual:
61 Expr = Expression.LessThanOrEqual(propertyReference, constantReference);
62 break;
63 case OperationType.Like:
64 Expr = Expression.Call(propertyReference, typeof(String).GetMethod("Contains", new Type[] { typeof(string) }), constantReference);
65 break;
66 default:break;
67
68 }
69
70 expression = Expression.AndAlso(expression, Expr); //最终的查询条件
71 }
72 }
73 return Expression.Lambda<Func<TSource, bool>>(expression, pe);
74 }
75 }

注意:必须将Query类和该类的成员方法定义为static,具体原因请搜索C#拓展方法的定义
最后,只需要在IQueryable对象上调用Search(查询条件对象)这个函数并传入参数就可以了 这是我自己定义的查询条件类

1 public class ProjectInfoDTO
2 {
3 [Search("CompanyName",OperationType.Like)]
4 public string CompanyName { get; set; }
5
6
7 [Search("SYS_CreateTime",OperationType.GreaterThanOrEqual)]
8 public DateTime? CreateTimeStart { get; set; }
9
10 [Search("SYS_CreateTime", OperationType.LessThanOrEqual)]
11 public DateTime? CreateTimeEnd { get; set; }
12 }

类的属性名称不一定要与属性上面Search方法的displayName参数的值相同,但是displayName参数的值必须与查询列表对象中属性的名称相同 这是我查询的列表

1 var result = (from a in db.Company_BasicInfo.Where(p => p.CompanyID > 0)
2 select new
3 {
4 a.CompanyID,
5 a.CompanyName,
6 a.SYS_CreateTime
7 }).Search(searchOption).OrderByDescending(p => p.SYS_CreateTime).Take(10000).ToList();

OK,现在我不需要管我的查询条件是什么了,只需要往查询属性的对象中传入对应的值即可
表达式树Expression的更多相关文章
- [C#] C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...
- 表达式树 Expression
转载泛型方法动态生成表达式树 Expression public string GetGridJSON(TraderInfo model) { IQueryable<TraderInfo> ...
- 表达式树(Expression Tree)
饮水思源 本文并非原创而是下面网址的一个学习笔记 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/e ...
- C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...
- 泛型方法动态生成表达式树 Expression
public string GetGridJSON(TraderInfo model) { IQueryable<TraderInfo> Temp = db.TraderInfo; if ...
- jQuery find() 搜索所有段落中的后代 C# find() 第一个匹配元素 Func 有返回值 Action是没有返回值 Predicate 只有一个参数且返回值为bool 表达式树Expression
所有p后代span Id为 TotalProject 的 select 标签 的后代 option标签 为选中的 text using System; using System.Collections ...
- 利用表达式树Expression优化反射性能
最近做了一个.Net Core环境下,基于NPOI的Excel导入导出以及Word操作的服务封装,涉及到大量反射操作,在性能优化过程中使用到了表达式树,记录一下. Excel导入是相对比较麻烦的一块, ...
- C# 表达式树 Expression
表达式树是定义代码的数据结构. 它们基于编译器用于分析代码和生成已编译输出的相同结构. 几种常见的表达式 BinaryExpression 包含二元运算符的表达式 BinaryExpression b ...
- Func委托与表达式树Expression
最近在写ORM框架,其中遇到一个难点,就是作为框架调用方如何将查询条件传入框架内.其中就用到了Expression. Func委托 要Expression先要了解Func委托,Func委托的样式是: ...
随机推荐
- 使用VHD,让Win XP和 Win2003 运行在内存中
通过一定的手段可以让XP和2003甚至Win7运行在内存中.我很感兴趣,于是按照网上的资料在VBox虚拟机中测试了一次,运行成功.这几天将其折腾到实体机上. 声明:我的做法和网上的做法有些不一样,我的 ...
- jquery的滚动事件
$(selector).scroll(function);当滚动到合适的条件下,就触发某个函数. 现在基本就是前端利用AJAX对数据进行拼接操作,渲染进html的DOM结构中.
- 最新GitHub账号注册(详细图解)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 一.简介 GitHub是一个面向开源及私有软件项目的托管平台,因为只支持git 作为唯一的版本库格式进行托管,故名gitHub. ...
- jmeter--九种定时器介绍(包括思考时间、集合点)
知识来源:http://www.cnblogs.com/imyalost/p/6004678.html jmeter提供了很多元件,帮助我们更好的完成各种场景的性能测试,其中,定时器(timer)是很 ...
- 嵌入式Linux学习笔记 NAND Flash控制器
一.NAND Flash介绍和NAND Flash控制器的使用 NAND Flash在嵌入式系统中的作用,相当于PC上的硬盘 常见的Flash有NOR Flash和NAND Flash,NOR Fla ...
- 每日技术总结:Better-scroll应用于弹出层内容滚动
一.Better-scroll在项目中的应用 Better-scroll这款滚动插件还是很好用的,通常不会有什么问题.但偶尔总会出点意外.今天再次使用better-scroll,记录一下这次顺利的过程 ...
- PHP的工作原理和生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u013778883/article/details/79831035 php是一门适用于web开 ...
- hcharts实现堆叠柱形图
<!DOCTYPE > <html> <head> <meta charset="utf-8"><link rel=" ...
- js静态私有变量(将方法变成原型模式,被所有实例共享,而方法操作变量,故变量是静态)
js静态私有变量(将方法变成原型模式,被所有实例共享,而方法操作变量,故变量是静态) 一.总结 1.js函数中的private和public:js函数中的私有变量 var 变量名,公有变量 this. ...
- 组合搜索(combinatorial search)在算法求解中的应用
1. 分治.动态规划的局限性 没有合适的分割方式时,就不能使用分治法: 没有合适的子问题或占用内存空间太大时,就不能用动态规划: 此时还需要回到最基本的穷举搜索算法. 穷举搜索(exhaustive ...