Linq动态查询简易解决之道(原创)
因为项目需要使用Linq来查询数据,但是在多条件查询时,需要使用一大堆if(...!=string.empty)等判断条件感觉不是很优雅。网上搜索以下,大概找到了两种办法,一种是老外写的一个类,感觉用着麻烦;还有就是提供一扩展个方法,参数为某个类型,当调用该方法时,用反射去遍历这个类型的属性,再拿动态查询参数和属性值去比较,然后构建动态lambda表达式,这个也有缺陷,就是需要遍历类型的所有属性,而且构建lambda表达式只能构建==类型表达式,有局限性。所以自己琢磨了一个办法,调用时只需一行代码,lambda表达式可以随意构建,现在进入主题。
假设有一个类型Employee,并且该类型有集合employeeList,有这样一个基于IEnumerable<T>类型的扩展方法Wheres(稍后介绍),那怎样用
一行代码employeeList.Wheres(o => o.Name == "a" && o.Salary > 5000 && o.InDate >= DateTime.Now && o.Address.Contains("北京"))去实现如下一堆代码:
if (!string.IsNullOrEmpty(name))
{
employeeList.Where(o => o.Name == name);
}
if (salary != null)参数设置为可空
{
employeeList.Where(o => o.Name == name);
}
if (inDate != null)
{
employeeList.Where(o => o.InDate>=inDate);
}
if (!string.IsNullOrEmpty(address))
{
employeeList.Where(o => o.Address.Contains("北京"));
}
因为Linq Lambda表达式在运行的时候会被解析成一棵表达式的二叉树,这棵树只允许左边的子节点存在BinaryExpression子节点,而右边的子节点不存在BinaryExpression子节点,但可以存在MemberExpression子节点(o.Name=="a"就是一个BinaryExpression,o.Name以及"a"就是BinaryExpression)。所以employeeList.Wheres(o => o.Name == "a" && o.Salary > 5000 && o.InDate >= DateTime.Now && o.Address == "北京")将会被解析成如下图的一个课二叉树:
我们只需找出红色节点,然后得到蓝色节点的值,然后去构建动态Lambda表达式就可以了,所以的获取节点的方法如下:
/// <summary>
/// 分解表达式树
/// </summary>
/// <param name="tree"></param>
/// <returns></returns>
private static Stack<Expression> DivideBinaryExpression(Expression expression)
{
Stack<Expression> stack = new Stack<Expression>(); if (expression.NodeType != ExpressionType.AndAlso) //为了简化调用代码,只允许根节点为&&
{
stack.Push(expression);
}
else
{
BinaryExpression tree = expression as BinaryExpression;
while (tree != null && tree.NodeType == ExpressionType.AndAlso)
{
stack.Push(tree.Right);
if (tree.Left.NodeType != ExpressionType.AndAlso)
{
stack.Push(tree.Left);
}
tree = tree.Left as BinaryExpression;//循环遍历表达式
}
}
return stack;
}
然后再根据得到的节点去动态构建Lambda表达式,方法如下:
/// <summary>
/// 多where子句查询
/// </summary>
/// <typeparam name="TSource">实体类型</typeparam>
/// <typeparam name="TResult">Expression的返回类型</typeparam>
/// <param name="t">实体集合</param>
/// <param name="expression">表达式</param>
/// <returns>实体集合</returns>
public static IEnumerable<TSource> Wheres<TSource>(this IEnumerable<TSource> t, Expression<Func<TSource, bool>> expression)
{
foreach (Expression e in DivideBinaryExpression(expression.Body))
{
object expressionValue = null;
if ((e as BinaryExpression) != null)
{
BinaryExpression be = e as BinaryExpression;
expressionValue = LambdaExpression.Lambda(be.Right).Compile().DynamicInvoke();
}
else //为了处理像o.Address.Contains("北京")这样的特殊节点
{
MethodCallExpression mce = e as MethodCallExpression;
expressionValue = LambdaExpression.Lambda(mce.Arguments[]).Compile().DynamicInvoke();
}
if (expressionValue != null)
{
if (!string.IsNullOrEmpty(expressionValue.ToString()))
t = t.Where(Expression.Lambda<Func<TSource, bool>>(e, expression.Parameters).Compile());
}
}
return t;
}
在调用的时候只需像上面提到的一行代码就够了,虽然不是很完善,但至少能解决90%以上的需求.
Linq动态查询简易解决之道(原创)的更多相关文章
- Linq动态查询与模糊查询 ---转
Linq动态查询与模糊查询(带源码示例) 继LINQ动态组合查询PredicateExtensions讲解 ----- 在用上面的方法时遇到了些问题 解决 LINQ to Entities 不支持 L ...
- Linq 动态查询排序
Linq的排序一般是这样写的: query.OrderBy(x => x.Tel).Skip().Take(); 实际使用中排序字段可能是通过字符类型的参数来设置的,于是想这样实现: query ...
- 表达式树在LINQ动态查询
动态构建表达式树,最佳实践版,很实用! public class FilterCollection : Collection<IList<Filter>> { public F ...
- c#——表达式树在LINQ动态查询
一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件 简单方式这样操作就可以了 public IQueryable<FileImport> DynamicCh ...
- Linq动态查询
public class ExpressionCall { List<Customer> customers = new List<Customer>() { new Cust ...
- linq字符串搜索条件,排序条件-linq动态查询语句 Dynamic LINQ
在做搜索和排序的时候,往往是前台传过来的字符串做条件,参数的数量还不定,这就需要用拼sql语句一样拼linq语句.而linq语句又是强类型的,不能用字符串拼出来. 现在好了,有个开源的linq扩展方法 ...
- LINQ动态查询类--[DynamicLinqExpressions]
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.L ...
- Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询
原文:Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询 如果允许在UI层直接访问Linq to Sql的DataContext,可以省去很多问题,譬如在处理多表join的时候, ...
- (转)QueryBuilder : 打造优雅的Linq To SQL动态查询
原文地址:http://www.cnblogs.com/coolcode/archive/2009/09/28/IQueryBuilder.html 首先我们来看看日常比较典型的一种查询Form 这个 ...
随机推荐
- MFC 网络编程 -- 总结
原文链接:http://www.cnblogs.com/lidabo/archive/2012/07/19/2598734.html 1.基于 TCP 的 socket 编程 /* 服务器端程序流程: ...
- 一对一关联查询时使用relation连贯操作查询后,调用getLastSql()方法输出的sql语句
如题: 一对一关联查询时使用relation连贯操作查询后,调用getLastSql()方法输出的sql语句不是一条关联查询语句. 例如: $list = $db->relation(true) ...
- Linux安装SmartSVN及破解
转载自:linux 下svn图形客户端smartsvn 安装 一.准备 smartsvn需要java支持,首先请确认机器上有没有安装java 另外还请确认环境变量里有没有JAVA_HO ...
- Hibernate基于注解方式配置来实现实体和数据库之间存在某种映射关系
实体和数据库之间存在某种映射关系,hibernate根据这种映射关系完成数据的存取.在程序中这种映射关系由映射文件(*.hbm.xml)或者java注解(@)定义. 本文以java注解的形式总结映射关 ...
- FOJ 1683 纪念SlingShot(矩阵快速幂)
C - 纪念SlingShot Description 已知 F(n)=3 * F(n-1)+2 * F(n-2)+7 * F(n-3),n>=3,其中F(0)=1,F(1)=3,F(2)=5, ...
- [转]ionic Accordion list three levels
简化后的主要代码: $scope.groups = []; for (var i = 0; i < 2; i++) { $scope.groups[i] = { name: i, items: ...
- ZBrush中的SubTool工具该怎样使用
今天的ZBrush教程中将为大家引入一个新的工具SubTool,使用SubTool您可以添加PolyMesh至当前编辑的模型中,它的出现改变了过去ZBrush不能同时编辑多个模型的弊端. 查看详细的视 ...
- Normalize.css的使用(重置表)
本文译自Normalize.css官网: http://nicolasgallagher.com/about-normalize-css/ Normalize.css 只是一个很小的CSS文件,但它在 ...
- python中怎么查看当前工作目录和更改工作目录
查询当前目录:os.getcwd() 更改当前目录:os.chdir()
- 2014 Super Training #1 C Ice-sugar Gourd 模拟,扫描线
原题 HDU 3363 http://acm.hdu.edu.cn/showproblem.php?pid=3363 给你一个串,串中有H跟T两种字符,然后切任意刀,使得能把H跟T各自分为原来的一半. ...