因为项目需要使用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表达式就可以了,所以的获取节点的方法如下:

  1. /// <summary>
  2. /// 分解表达式树
  3. /// </summary>
  4. /// <param name="tree"></param>
  5. /// <returns></returns>
  6. private static Stack<Expression> DivideBinaryExpression(Expression expression)
  7. {
  8. Stack<Expression> stack = new Stack<Expression>();
  9.  
  10. if (expression.NodeType != ExpressionType.AndAlso) //为了简化调用代码,只允许根节点为&&
  11. {
  12. stack.Push(expression);
  13. }
  14. else
  15. {
  16. BinaryExpression tree = expression as BinaryExpression;
  17. while (tree != null && tree.NodeType == ExpressionType.AndAlso)
  18. {
  19. stack.Push(tree.Right);
  20. if (tree.Left.NodeType != ExpressionType.AndAlso)
  21. {
  22. stack.Push(tree.Left);
  23. }
  24. tree = tree.Left as BinaryExpression;//循环遍历表达式
  25. }
  26. }
  27. return stack;
  28. }

然后再根据得到的节点去动态构建Lambda表达式,方法如下:

  1. /// <summary>
  2. /// 多where子句查询
  3. /// </summary>
  4. /// <typeparam name="TSource">实体类型</typeparam>
  5. /// <typeparam name="TResult">Expression的返回类型</typeparam>
  6. /// <param name="t">实体集合</param>
  7. /// <param name="expression">表达式</param>
  8. /// <returns>实体集合</returns>
  9. public static IEnumerable<TSource> Wheres<TSource>(this IEnumerable<TSource> t, Expression<Func<TSource, bool>> expression)
  10. {
  11. foreach (Expression e in DivideBinaryExpression(expression.Body))
  12. {
  13. object expressionValue = null;
  14. if ((e as BinaryExpression) != null)
  15. {
  16. BinaryExpression be = e as BinaryExpression;
  17. expressionValue = LambdaExpression.Lambda(be.Right).Compile().DynamicInvoke();
  18. }
  19. else //为了处理像o.Address.Contains("北京")这样的特殊节点
  20. {
  21. MethodCallExpression mce = e as MethodCallExpression;
  22. expressionValue = LambdaExpression.Lambda(mce.Arguments[]).Compile().DynamicInvoke();
  23. }
  24. if (expressionValue != null)
  25. {
  26. if (!string.IsNullOrEmpty(expressionValue.ToString()))
  27. t = t.Where(Expression.Lambda<Func<TSource, bool>>(e, expression.Parameters).Compile());
  28. }
  29. }
  30. return t;
  31. }

在调用的时候只需像上面提到的一行代码就够了,虽然不是很完善,但至少能解决90%以上的需求.

Linq动态查询简易解决之道(原创)的更多相关文章

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

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

  2. Linq 动态查询排序

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

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

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

  4. c#——表达式树在LINQ动态查询

    一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件 简单方式这样操作就可以了 public IQueryable<FileImport> DynamicCh ...

  5. Linq动态查询

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

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

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

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

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

  8. Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询

    原文:Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询 如果允许在UI层直接访问Linq to Sql的DataContext,可以省去很多问题,譬如在处理多表join的时候, ...

  9. (转)QueryBuilder : 打造优雅的Linq To SQL动态查询

    原文地址:http://www.cnblogs.com/coolcode/archive/2009/09/28/IQueryBuilder.html 首先我们来看看日常比较典型的一种查询Form 这个 ...

随机推荐

  1. python基本数据结构-集合-方法

  2. Hive安装(三)之奇怪的错误

    启动hive命令报错 “Metastore contains multiple versions” 解决方案: 因为hive metastore存储在mysql中,所以登录mysql,use hive ...

  3. 安装node.js+express for win7的Web开发环境配置

    1.安装 node.js. 进入官网的下载地址:http://www.nodejs.org/download/ . 选择Windows Installer或者选择Windows Installer ( ...

  4. cocos2d-x之Vector与map

    bool HelloWorld::init() { if ( !Layer::init() ) { return false; } Size visibleSize = Director::getIn ...

  5. 在jsp中默认写上的一段java代码表示basePath 的路径的具体的意思是什么?

    <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" ...

  6. XUtils===XUtils3框架的基本使用方法

    转载自:http://blog.csdn.NET/a1002450926/article/details/50341173 今天给大家带来XUtils3的基本介绍,本文章的案例都是基于XUtils3的 ...

  7. Unity摄像机的正交视图与透视图

    Unity Camera的两种模式 Projection:投射,投影 Unity的MainCamera的Projection可选择Perspective[透视],Orthographic[正交],是指 ...

  8. unity3d Aniso Level 摄像机近地面清楚,远地面模糊

    设置方法 选中贴图 在属性面板,拖动Aniso Level的值从0~9改变,值越大贴图越清晰,但是消耗也变大,文档说会造成显卡消耗,一般只用在地面上,其他地方没必要 遇到的问题 但是打包到Ipod上面 ...

  9. java8-1 final

    1.final可以修饰类,方法,变量 特点: final可以修饰类,该类不能被继承. final可以修饰方法,该方法不能被重写.(覆盖,复写) final可以修饰变量,该变量不能被重新赋值.因为这个变 ...

  10. Android优化——UI优化(四) 使用stytle

    使用style替换背景,防止Activity黑色背景闪过 1.原来的布局 <LinearLayout xmlns:android="http://schemas.android.com ...