Expression表达式树动态查询

在进行数据列表的查询中,我们通常会使用两种方式进行查询:
  1. linq查询
  2. 数据库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的更多相关文章

  1. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  2. 表达式树 Expression

    转载泛型方法动态生成表达式树 Expression public string GetGridJSON(TraderInfo model) { IQueryable<TraderInfo> ...

  3. 表达式树(Expression Tree)

    饮水思源 本文并非原创而是下面网址的一个学习笔记 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/e ...

  4. C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  5. 泛型方法动态生成表达式树 Expression

    public string GetGridJSON(TraderInfo model) { IQueryable<TraderInfo> Temp = db.TraderInfo; if ...

  6. jQuery find() 搜索所有段落中的后代 C# find() 第一个匹配元素 Func 有返回值 Action是没有返回值 Predicate 只有一个参数且返回值为bool 表达式树Expression

    所有p后代span Id为 TotalProject 的 select 标签 的后代 option标签 为选中的 text using System; using System.Collections ...

  7. 利用表达式树Expression优化反射性能

    最近做了一个.Net Core环境下,基于NPOI的Excel导入导出以及Word操作的服务封装,涉及到大量反射操作,在性能优化过程中使用到了表达式树,记录一下. Excel导入是相对比较麻烦的一块, ...

  8. C# 表达式树 Expression

    表达式树是定义代码的数据结构. 它们基于编译器用于分析代码和生成已编译输出的相同结构. 几种常见的表达式 BinaryExpression 包含二元运算符的表达式 BinaryExpression b ...

  9. Func委托与表达式树Expression

    最近在写ORM框架,其中遇到一个难点,就是作为框架调用方如何将查询条件传入框架内.其中就用到了Expression. Func委托 要Expression先要了解Func委托,Func委托的样式是: ...

随机推荐

  1. Serializable中的serialVersionUID到底有啥用

    最近在研究跨进程通信的问题,于是又再一次研究了,我们熟悉而又陌生的Serializable接口. 那么好,做过Java开发的朋友肯定对这个接口不陌生吧,Java中就是通过这个接口,来实现了序列化和反序 ...

  2. [D3] Debug D3 v4 with Dev Tools

    Since D3 outputs standard markup, you can use familiar dev tools and inspectors to debug your visual ...

  3. Cscope how to support java and c++

    Cscope 首先在文件夹下建立cscope索引文件 find -name '*.c' > cscope.file cscope -Rbkq 这个命令会生成三个文件:cscope.out, cs ...

  4. 几个移动web app开发框架

    几个移动web app开发框架 一.总结 1.有amaze ui,有app.js(登录注册界面用到的)  二.几个移动web app开发框架 jQuery Mobile jQuery Mobile框架 ...

  5. mangodb学习0.1 概念

    摘自菜鸟教程

  6. SoC的Testbench中的简易bus_monitor(加入print函数)

    SoC的Testbench中的简易bus_monitor(加入print函数) 主要思路 向固定地址写信息 使用工具链将C写的print/printf函数编译成hex文件 在testbench中创建b ...

  7. 得到INI文件所有Section(所有节点名称)

    char SectionNames[MAX_PATH],*pSectionName; ZeroMemory(SectionNames,MAX_PATH); GetPrivateProfileSecti ...

  8. 【Codeforces Round #439 (Div. 2) C】The Intriguing Obsession

    [链接] 链接 [题意] 给你3种颜色的点. 每种颜色分别a,b,c个. 现在让你在这些点之间加边. 使得,同种颜色的点之间,要么不连通,要么连通,且最短路至少为3 边是无向边. 让你输出方案数 [题 ...

  9. 细说HTML头部标签

    原文 简书原文:https://www.jianshu.com/p/4270b1d1037d 大纲 1.头部标签列表 2.头部标签详解 1.头部标签列表 <!DOCTYPE html> & ...

  10. C++实现简单的内存块自己主动管理

    #ifndef __MEM__H #define __MEM__H #include<iostream> using namespace std; //自己主动管理内存块 typedef ...