Expression表达式树动态查询
在进行数据列表的查询中,我们通常会使用两种方式进行查询:
- linq查询
- 数据库sql语句查询
这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少。使用linq,可以将所有的查询条件的属性传到后台,再根据该属性是否有值,使用where进行查询;使用存储过程,也需要将所有查询条件的属性传到后台,
再根据该属性是否有值进行sql语句的拼接。这样做在查询条件很少的时候固然没啥影响,但是有一天做查询列表的时候,本人碰到了一个查询条件高达接近10个的情况,这样再使用上述的方法固然也可以实现,但是可能会使用多个
条件去判断,然后使用多个where查询,如果在数据库使用sql语句拼接,可能会产生很长的sql拼接查询的代码,在调试的时候还要用print去打印才能看到完整的查询条件,所以我就想,能不能写一种方法可以动态产生查询的条件
,不管列表的查询条件有十个还是几十个,我只需要将查询的属性作为一个对象传到后台,再将这个查询属性的对象丢给这个方法,让它动态产生查询的表达式,然后使用linq中的where去查询呢?于是我便踏上了探索Expression表
达式树的路途!下面我写出自己的代码,希望和大家能一起交流学习!
经过查询资料和研究,终于写出了以下这套代码来达到目的:
1.定义一个查询的特性类,_displayName用于指明查询条件的类的各个属性用于和数据源列表元素对象的各个属性比较的属性名称(注意:_displayName的值必须和数据源中各个属性名称相同),_operation用于指明比较的操作
类型,类的代码如下:
public class SearchAttribute : Attribute
{
/// <summary>
/// 属性名称,用于对比查询
/// </summary>
private string _displayName;
/// <summary>
/// 操作类型
/// </summary>
private OperationType _operation; public string DisplayName
{
get { return _displayName; }
}
public OperationType Operation
{
get { return _operation; }
} public SearchAttribute(string displayName, OperationType operation)
{
_displayName = displayName;
_operation = operation;
} /// <summary>
/// 不是查询的条件时调用此构造函数 参数值=OperationType.None
/// </summary>
/// <param name="operation"></param>
public SearchAttribute(OperationType operation)
{
_operation = operation;
}
}
2.定义一个比较的操作类型的枚举类型
/// <summary>
/// 查询操作类型
/// </summary>
public enum OperationType
{
/// <summary>
/// 不进行查询
/// </summary>
None,
/// <summary>
/// 比较该查询属性的值是否与元数据数据的值相等 即sql中=
/// </summary>
Equal,
/// <summary>
/// 比较元数据数据的值是否包含该查询属性的值 即sql中like
/// </summary>
Like,
/// <summary>
/// 大于
/// </summary>
GreaterThan,
/// <summary>
/// 小于
/// </summary>
LessThan,
/// <summary>
/// >=
/// </summary>
GreaterThanOrEqual,
/// <summary>
/// <=
/// </summary>
LessThanOrEqual
}
3.核心代码来了,哈哈
public static class Query
{
public static IQueryable<TSource> Search<TSource,T>(this IQueryable<TSource> queryList, T searchOptions)
{
return queryList.Where(Search<TSource,T>(searchOptions));
} private static Expression<Func<TSource, bool>> Search<TSource,T>(T searchOptionEntity)
{
var dataSouceType = typeof(TSource); //数据源列表元素对象的类型
var dataSource = new
{
Type = dataSouceType, //数据源列表元素对象的类型
Properties = dataSouceType.GetProperties(), //数据源列表元素对象的属性集合
}; //List<string> sourcePropertyName = sourceProperties.Select(p => p.Name).ToList(); PropertyInfo[] searchProperties = searchOptionEntity.GetType().GetProperties(); //查询选择器对象的属性集合 var pe = Expression.Parameter(dataSource.Type, "p"); //创建一个 ParameterExpression 节点,该节点可用于标识表达式树中的参数或变量
var expression = Expression.Equal(Expression.Constant(true), Expression.Constant(true)); //遍历查询选择器对象的属性集合
foreach (var property in searchProperties)
{
var propertySearchAttribute = property.GetCustomAttributes(true)[] as SearchAttribute; //获取查询选择器属性的自定义特性对象
var propertySearchVlaue = property.GetValue(searchOptionEntity, null); //获取查询选择器属性的值
var propertySearchAttributeName = propertySearchAttribute.DisplayName; //获取查询选择器属性的自定义特性对象的对比查询的字段名称 //查询选择器中的该属性的自定义的对比查询的字段名称 in 数据源列表对象的属性集合 && 查询选择器中的该属性是查询的条件 && 查询选择器该属性的值!=null或者""
if (Array.Exists(dataSource.Properties, p => p.Name == propertySearchAttributeName) && propertySearchAttribute.Operation!=OperationType.None && propertySearchVlaue != null && propertySearchVlaue != (object)string.Empty)
{
var propertyReference = Expression.Property(pe, propertySearchAttributeName);
var sourcePropertyType = dataSource.Properties.FirstOrDefault(p => p.Name == propertySearchAttributeName).PropertyType; //获取数据源列表元素对象的单个属性的属性类型
ConstantExpression constantReference = null;
Expression Expr = null; bool isGenericType = sourcePropertyType.IsGenericType && sourcePropertyType.GetGenericTypeDefinition() == typeof(Nullable<>); //搜索sourcePropertyType是否可为空
if (isGenericType)
constantReference = Expression.Constant(Convert.ChangeType(propertySearchVlaue, Nullable.GetUnderlyingType(sourcePropertyType)), sourcePropertyType); //如果可为空类型,则将propertySearchVlaue的类型设置为可为空类型
else
constantReference = Expression.Constant(Convert.ChangeType(propertySearchVlaue, sourcePropertyType)); //根据查询选择器中该属性的查询条件进行不同的操作
switch (propertySearchAttribute.Operation)
{
case OperationType.Equal:
Expr = Expression.Equal(propertyReference, constantReference);
break;
case OperationType.GreaterThan:
Expr = Expression.GreaterThan(propertyReference, constantReference);
break;
case OperationType.LessThan:
Expr = Expression.LessThan(propertyReference, constantReference);
break;
case OperationType.GreaterThanOrEqual:
Expr = Expression.GreaterThanOrEqual(propertyReference, constantReference);
break;
case OperationType.LessThanOrEqual:
Expr = Expression.LessThanOrEqual(propertyReference, constantReference);
break;
case OperationType.Like:
Expr = Expression.Call(propertyReference, typeof(String).GetMethod("Contains", new Type[] { typeof(string) }), constantReference);
break;
default:break; } expression = Expression.AndAlso(expression, Expr); //最终的查询条件
}
}
return Expression.Lambda<Func<TSource, bool>>(expression, pe);
}
}
注意:必须将Query类和该类的成员方法定义为static,具体原因请搜索C#拓展方法的定义
最后,只需要在IQueryable对象上调用Search(查询条件对象)这个函数并传入参数就可以了 这是我自己定义的查询条件类
public class ProjectInfoDTO
{
[Search("CompanyName",OperationType.Like)]
public string CompanyName { get; set; } [Search("SYS_CreateTime",OperationType.GreaterThanOrEqual)]
public DateTime? CreateTimeStart { get; set; } [Search("SYS_CreateTime", OperationType.LessThanOrEqual)]
public DateTime? CreateTimeEnd { get; set; }
}
类的属性名称不一定要与属性上面Search方法的displayName参数的值相同,但是displayName参数的值必须与查询列表对象中属性的名称相同 这是我查询的列表
var result = (from a in db.Company_BasicInfo.Where(p => p.CompanyID > )
select new
{
a.CompanyID,
a.CompanyName,
a.SYS_CreateTime
}).Search(searchOption).OrderByDescending(p => p.SYS_CreateTime).Take().ToList();
OK,现在我不需要管我的查询条件是什么了,只需要往查询属性的对象中传入对应的值即可
Expression表达式树动态查询的更多相关文章
- 介绍一个可以将Expression表达式树解析成Transact-SQL的项目Expression2Sql
一.Expression2Sql介绍 Expression2Sql是一个可以将Expression表达式树解析成Transact-SQL的项目.简单易用,几分钟即可上手使用,因为博主在设计Expres ...
- 委托、匿名委托、Lambda 表达式、Expression表达式树之刨根问底
本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景.各位看官,这里就不啰嗦了,直接上代码. 首先定义一个泛型委托类型,如下: public delegate T Function&l ...
- .net 系列:Expression表达式树、lambda、匿名委托 的使用
首先定义一个泛型委托类型,如下: public delegate T Function<T>(T a, T b); 实现泛型委托的主体代码,并调用: public static strin ...
- .net 系列:Expression表达式树、lambda、匿名委托 的使用【转】
https://www.cnblogs.com/nicholashjh/p/7928205.html 首先定义一个泛型委托类型,如下: public delegate T Function<T& ...
- Expression表达式树(C#)
Lambda表达式: 1.下面举例通过Lambda表达式创建了一个用于验证Name的Func委托. //通过Lambda表达式创建一个对象的Name属性验证委托 Func<SearchInfo, ...
- .NET技术-6.0. Expression 表达式树 生成 Lambda
.NET技术-6.0. Expression 表达式树 生成 Lambda public static event Func<Student, bool> myevent; public ...
- 关于Expression表达式树的拼接
最近在做项目中遇到一个问题,需求是这样的: 我要对已经存在的用户进行检索,可以根据用户的id 或者用户名其中的一部分字符来检索出来,这样就出现了三种情况 只有id,只有用户名中一部字符,或者全部都有. ...
- 表达式树动态拼接lambda
动态拼接lambda表达式树 前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dappe ...
- C#使用表达式树动态调用方法并实现99乘法表
我们在使用C#编程的时候,经常使用反射来动态调用方法,但有时候需要动态的生成方法,下面介绍使用表达式树的方式来自动生成方法,并调用. 首先需要说明什么是表达式,熟悉Linq的程序猿都用过类似于下面的代 ...
随机推荐
- JNDI常见配置方式
JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API.命名服务将名称和对象联系起来,使得我们可以用 ...
- 提问!同一ajax请求获取的图片路劲,在谷歌浏览器能正确展示图片,在火狐浏览器则显示路径undefined
今天的工作学习之路遇见一个奇葩的问题,作为初级攻城狮的小生实在不知如何解决,都已经壁咚度娘一整天了,都未能解决问题,实属无奈,一开始认为是浏览器兼容的问题,但左看右看,也不是,也尝试过是不是页面加载与 ...
- 实现Unity编辑器模式下的旋转
最近在做一个模型展示的项目,我的想法是根据滑动屏幕的x方向差值和Y方向的差值,来根据世界坐标下的X轴和Y轴进行旋转,但是实习时候总是有一些卡顿.在观察unity编辑器下的旋转之后,发现编辑器下的旋转非 ...
- AutoIt 脚本小试——刷网易云音乐歌单
AutoIt 确实是个很强大的脚本工具. 如果早知道有这个,当初是怎么都不会去学易语言的 (๑•̀ω•́๑) 这是个简单脚本 = ๛ก(ー̀ωー́ก) 用来增加歌单播放次数和个人的听歌量. 原理不过 ...
- celldb.cc
欢迎光临 celldb.cc 的新博客 老博客的内容就不搬迁了, 工作量太大. http://celldb.cc 主要功能: 1 话单基站轨迹分析 2 基站查询 3 邻近基站查询 4 CDMA根据城市 ...
- 视频swiper轮播
关于本次文章的内容,实际上是咪咕阅读详情页中的一个前端需求要做的效果,不过比起原需求,此次案例已经被删减掉许多部分了.音频部分舍弃,调用客户端接口舍弃,并做一些整理.最后留下的是这个精简版的案例.方便 ...
- Jmeter-添加检查点
JMeter里面的检查点通过添加断言来完成. 检查用户名和密码参数化的文件user.dat有没有正确调用,添加断言,可以在结果树中查看结果. 1.添加响应断言,右键点击HTTP请求"ts1后 ...
- 第三方登录 ----QQ登录
学习之前,请大家先看一下oAuth协议. 首先呢,我们进入QQ互联的官方网站 http://connect.qq.com登入我们自己的QQ号,没有QQ号的小伙伴可以忽略本篇博文分享!
- Python Selenium设计模式-POM
前言 本文就python selenium自动化测试实践中所需要的POM设计模式进行分享,以便大家在实践中对POM的特点.应用场景和核心思想有一定的理解和掌握. 为什么要用POM 基于python s ...
- java实现截屏
import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit ...