zoukankan      html  css  js  c++  java
  • 使用Expression Tree构建动态LINQ查询

    这篇文章介绍一个有意思的话题,也是经常被人问到的:如何构建动态LINQ查询?所谓动态,主要的意思在于查询的条件可以随机组合,动态添加,而不是固定的写法。这个在很多系统开发过程中是非常有用的。

    我这里给的一个解决方案是采用Expression Tree来构建。

    其实这个技术很早就有,在.NET Framework 3.5开始引入。之前也有不少同学写过很多不错的理论性文章。我自己当年学习这个,觉得最好的几篇文章是由"装配脑袋"同学写的。【有时间请仔细阅读这些入门指南,做点练习基本就能理解】

    Expression Tree上手指南 (一) - 装配脑袋 - 博客园

    Expression Tree 上手指南 (二) - 装配脑袋 - 博客园

    Expression Tree 上手指南 (三) - 装配脑袋 - 博客园

     

    我下面给出的这个实例,希望能帮助大家更加深入理解这个技术,并且结合常见的LINQ to SQL来实现动态的查询。

    下面这个查询,大家应该都很眼熟

    如果我们的条件是固定的,例如上例中,一共有两个条件,而且条件的逻辑判断也都是确定的,那么上面这样写很容易就能得到我们的结果。

    但,问题是,如果我们的条件不是固定的呢?如果你需要根据用户的选择,然后动态构造一个查询呢?

    我看过很多人做的一些通用查询界面,为了应对用户希望自主选择条件的这个需求,他们的做法往往就是用"拼接查询字符串"的做法来实现。这种方法勉强能实现要求,但性能和可维护性方面都相当差。

    如果你了解了Expression Tree,那么上面这个查询可以修改为下面这样:

     

    由此可见,掌握了这个技术的话,那么以后写动态查询应该会如虎添翼,至少多了一种很好的思路。

    顺便说一下,这个技术和反射有点类似,属于比较底层的技术,掌握了将对大家的编程能力会有所提升。

    值得一说的是,就算是我们第一种写法,内部的实现也是使用Expression Tree来实现的,有兴趣的同学可以看看如下的IL代码。

    IL_0001: ldarg.0

    IL_0002: call LINQPad.User.TypedDataContext.get_Employees

    IL_0007: ldtoken LINQPad.User.Employees

    IL_000C: call System.Type.GetTypeFromHandle

    IL_0011: ldstr "x"

    IL_0016: call System.Linq.Expressions.Expression.Parameter

    IL_001B: stloc.1 // CS$0$0000

    IL_001C: ldloc.1 // CS$0$0000

    IL_001D: ldtoken LINQPad.User.Employees.EmployeeID

    IL_0022: call System.Reflection.FieldInfo.GetFieldFromHandle

    IL_0027: call System.Linq.Expressions.Expression.Field

    IL_002C: ldc.i4.5

    IL_002D: box System.Int32

    IL_0032: ldtoken System.Int32

    IL_0037: call System.Type.GetTypeFromHandle

    IL_003C: call System.Linq.Expressions.Expression.Constant

    IL_0041: call System.Linq.Expressions.Expression.GreaterThan

    IL_0046: ldloc.1 // CS$0$0000

    IL_0047: ldtoken LINQPad.User.Employees.Title

    IL_004C: call System.Reflection.FieldInfo.GetFieldFromHandle

    IL_0051: call System.Linq.Expressions.Expression.Field

    IL_0056: ldstr "Sales Representative"

    IL_005B: ldtoken System.String

    IL_0060: call System.Type.GetTypeFromHandle

    IL_0065: call System.Linq.Expressions.Expression.Constant

    IL_006A: ldc.i4.0

    IL_006B: ldtoken System.String.op_Equality

    IL_0070: call System.Reflection.MethodBase.GetMethodFromHandle

    IL_0075: castclass System.Reflection.MethodInfo

    IL_007A: call System.Linq.Expressions.Expression.Equal

    IL_007F: call System.Linq.Expressions.Expression.AndAlso

    IL_0084: ldc.i4.1

    IL_0085: newarr System.Linq.Expressions.ParameterExpression

    IL_008A: stloc.2 // CS$0$0001

    IL_008B: ldloc.2 // CS$0$0001

    IL_008C: ldc.i4.0

    IL_008D: ldloc.1 // CS$0$0000

    IL_008E: stelem.ref

    IL_008F: ldloc.2 // CS$0$0001

    IL_0090: call System.Linq.Expressions.Expression.Lambda

    IL_0095: call System.Linq.Queryable.Where

    IL_009A: stloc.0 // query

    IL_009B: ldloc.0 // query

    IL_009C: call LINQPad.Extensions.Dump

     

  • 相关阅读:
    Python安装(小白教程)中文版Pycharm
    二叉树遍历1
    node* p 和 node *p 和 node * p 的区别
    WinForm中的ListBox组件编程
    C# winform listBox中的项上下移动(转)
    C# ListBox 左移、右移、上移、下移
    C#上移,下移TreeView中的树节点顺序
    C#遍历DataSet与DataSet元素实现代码
    C# 手动编写 DataSet,DataTable 及遍历DataSet中的数据
    【.NET】C#中遍历各类数据集合的方法
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/3916630.html
Copyright © 2011-2022 走看看