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

     

  • 相关阅读:
    软件体系架构复习要点
    Operating System on Raspberry Pi 3b
    2019-2020 ICPC North-Western Russia Regional Contest
    2019 ICPC ShenYang Regional Online Contest
    2019 ICPC XuZhou Regional Online Contest
    2019 ICPC NanChang Regional Online Contest
    2019 ICPC NanJing Regional Online Contest
    Codeforces Edu Round 72 (Rated for Div. 2)
    Codeforces Round #583 (Div.1+Div.2)
    AtCoder Beginning Contest 139
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/3916630.html
Copyright © 2011-2022 走看看