.NET深入解析LINQ框架(六:LINQ执行表达式)

简介: 阅读目录: 1.LINQ执行表达式 在看本篇文章之前我假设您已经具备我之前分析的一些原理知识,因为这章所要讲的内容是建立在之前的一系列知识点之上的,为了保证您的阅读顺利建议您先阅读本人的LINQ系列文章的前几篇或者您已经具备比较深入的LINQ原理知识体系,防止耽误您的宝贵时间。

阅读目录:

  • 1.LINQ执行表达式

在看本篇文章之前我假设您已经具备我之前分析的一些原理知识,因为这章所要讲的内容是建立在之前的一系列知识点之上的,为了保证您的阅读顺利建议您先阅读本人的LINQ系列文章的前几篇或者您已经具备比较深入的LINQ原理知识体系,防止耽误您的宝贵时间。

到目前为止我们对LINQ的执行原理已经很清楚了,从它的前期构想到它真正为我们所用都有足够的证据,但是似乎问题并没有我们想的那么简单,问题总是在我们使用中频频出现尤其是新技术的使用,当然有问题才能有进步。

一:LINQ执行表达式

在研究LINQ的过程中,参考了很多技术文章还有技术书籍,毫无疑问的是Linq to Provider的调用入口都是将Lambda表达式解析成Expression<T>表达式对象,跟Linq to Object不同,Linq to Object是将Lambda直接解析成泛型Func类型的委托,但是我们很多人包括我自己都忽视了一个很大的细节,就是Provider在内部将对Expression<T>进行执行,并非我们所理解的那样将表达式Expression<T>对象完全解析成等价的SQL,也就是说Expression<T>并不是我们说看到的那样单纯,它具有双重上下文逻辑在里面。

我们都是直接使用LINQ作为查询接口,VS在最后编译的时候负责对LINQ的语法进行解析并且翻译成对应的扩展方法调用。我们忽视一个重要的环节,就是VS对LINQ进行解析翻译的时候是会执行LINQ表达式的,这点非常重要。之前我一直以为VS只负责将LINQ的表达式翻译成等价的扩展方法调用,后来发现VS为了满足我们在前期无法确定对象条件的情况下进行Where字句的拼接,允许我们在编写LINQ语句的时候带有逻辑判断表达式在里面,这个功能对我们进行多条件组合查询时相当方便,不需要在进行IF、ELSE的多个判断,只需要顺其自然的在LINQ中的第一个表达式中进行判断就行了。追求优雅代码的同志很不希望在一个既有LINQ查询又带有链式查询的方法中用两种查询方式,如果LINQ能满足大部分的查询功能那最完美;

为了说明LINQ在编译时会被VS执行,我们用LINQPad工具看一下便知;

LINQ查询表达式:from truck in TB_CX_TRUCKs where 1==1 select truck

LINQ等价的链式方法: TB_CX_TRUCKs.Where (truck => True)

图1:

如果没有执行按道理是直接解析成Lambda的格式(truck)=>1==1才对,然后让LINQ to Provider提供程序负责处理才对,也许觉得没有实质的意思反正是恒等的表达式所以解析成这样。我们在换一种写法看看;

LINQ查询表达式:from truck in TB_CX_TRUCKs where string.IsNullOrEmpty("1111") select truck

LINQ等价的链式方法:TB_CX_TRUCKs.Where (truck => String.IsNullOrEmpty ("1111"))

图2:

由此可以得出一个结论,LINQ语句是会被执行和解析的两个动作,在还没有进入到提供程序时已经可以看出LINQ是可以附带一些执行逻辑在里面的,而不是最终的SQL执行逻辑。

表达式的处理可以分为常量表达式和动态变量表达式,常量表达式在VS编译的时候就可以直接计算表达式是否是true、false。而动态变量表达式则需要在后期进行表达式解析的时候计算的,换句话说Linq to Provider中的Provider提供程序是具有高智商的表达式执行器,不仅仅是对表达式等价解析中间还夹杂着对表达式解析的自定义逻辑代码。

打个比方,我们都有过拼接查询条件的经历,界面上有N个查询条件字段,需要根据用户是否填写了哪个字段进行动态的拼接进LINQ语句中去。一般我们都会进行if的判断才行,因为我们都觉得Where后面的条件表达式是直接被解析成对应逻辑的SQL语句,所以只要拼接进去的都是被解析成SQL的Where子句。由于LINQ是无法拆分开来进行组装的,必须一次写完才能通过编译。所以我们都在使用着查询扩展方法进行数据查询,这样的困境使我们无法看到LINQ的优雅,反而一直用不到。

通过观察LINQPad工具解析的SQL语句,发现LINQ查询表达式在提供程序内部将被执行、解析两个过程,跟VS的过程是一样的,能执行先执行,然后解析,解析是建立在前期执行过后的基础上的。我们还是来看一个比较简单的LINQ解析后的SQL和链式方法;

LINQ查询表达式:from truck in TB_CX_TRUCKs where 1==1 ||truck.LICENSE_NUMBER.Length<10 select truck

LINQ等价的链式方法:TB_CX_TRUCKs.Where (truck => (True || (truck.LICENSE_NUMBER.Length < 10)))

图3:

对照链式方法,很明显VS先对1==1表达式进行了执行并返回true作为后面整个表达式的一部分拼接进Where链式方法,所以先执行再解析两个过程。然后我们对最后的SQL进行分析,没有看见任何Where语句,为什么呢?是因为提供程序在内部对表达式进行了执行并分析了我们想要的输出结果,也不知道这样的效果是不是为了满足我们多条件拼接的问题。

由于Where方法里面的Lambda表达如果被执行的话,那么将不会执行(truck.LICENSE-NUMBER.Length<10),所以这点为我们的多条件拼接提供了接口。

我们看一下多条件组合查询示例:

将界面上的查询实体传入到数据访问层之后:

View Code
 1 public List<Truck> GetList(Truck truckModel) 
 2 { 
 3     using (KJtest0817Entities DbContext = new KJtest0817Entities()) 
 4     { 
 5         var resultList = from truck in DbContext.TB_CX_TRUCK 
 6                          where string.IsNullOrEmpty(truckModel.ENGINE_NUMBER) || truck.ENGINE_NUMBER == truckModel.ENGINE_NUMBER 
 7                          where string.IsNullOrEmpty(truckModel.LICENSE_NUMBER) || truck.ENGINE_NUMBER == truckModel.LICENSE_NUMBER 
 8                          select new Truck() 
 9                          { 
10                              BRAND = truck.BRAND 
11                          }; 
12         return resultList.ToList(); 
13     } 
14 }

这样的查询LINQ确实很优美,比起之前的IFELSE判断也省事很多。

View Code
1 IQueryable<TB_CX_TRUCK> queryList = DbContext.TB_CX_TRUCK.AsQueryable();//初始化一个IQueryable对象 
2 if (!string.IsNullOrEmpty(truckModel.LICENSE_NUMBER)) 
3        queryList = queryList.Where(truck => truck.LICENSE_NUMBER.Contains(truckModel.LICENSE_NUMBER)); 
4 if (!string.IsNullOrEmpty(truckModel.TRUCK_MODEL_CODE)) 
5        queryList = queryList.Where(truck => truck.TRUCK_MODEL_CODE.Contains(truckModel.TRUCK_MODEL_CODE));

如果有很多个查询条件,那么我们将要写很多这样的判断代码,即不方便也不美观。

(注:查看大图)

多条件之间的OR查询

尽管很多场合下我们都是使用Linq中的where关键字来拼接查询条件,但是有一种需求Linq查询确实满足不了我们,那就是多条件之间是OR的关系。因为只要我们用Linq或者链式方法出来的写出来的SQL语句中的where条件后面将都是and关系,这个时候我们只能用链式方法来进行拆分才行。

View Code
 1 public List<DutyModel> GetList(DutyModel dutyModel) 
 2 { 
 3     using (UserOrgDemo2Entities Context = new UserOrgDemo2Entities()) 
 4     { 
 5         IQueryable<TB_DUTY> result = Context.TB_DUTY.AsQueryable(); 
 6         System.Linq.Expressions.Expression<Func<TB_DUTY, bool>> expressionDUTY = DynamicLinqExpressions.True<TB_DUTY>(); 
 7 
 8         if (!(dutyModel.RANK_NO == 0)) 
 9             expressionDUTY.Or(duty => duty.RANK_NO == dutyModel.RANK_NO); 
10         if (!string.IsNullOrEmpty(dutyModel.USER_PRIV)) 
11             expressionDUTY.Or(duty => duty.USER_PRIV == dutyModel.USER_PRIV); 
12 
13        return result.Where(expressionDUTY).Select(tb_duty=>new DutyModel(){ USER_PRIV=tb_duty.USER_PRIV}).ToList(); 
14     } 
15 }

这里有个重点就是老外(估计是比较厉害的前辈,在此谢谢了!)写的一个*.cs文件,里面是Expression<T>表达式文件的扩展方法,主要就是用来进行多条件Or、And之间组合查询用的。

所有说如果多条件组合查询之间是and关系可以直接使用Linq,如果是or或者是or与and一起,那么可以使用上面这种链式查询方法。

总结:其实说了那么多目的只有一个,LINQ的解析过程并非只有一个“提供程序翻译成SQL”的过程,而是包括了两个阶段,四个过程的处理,LINQ的写法很多种,原理应该是差不多的,只要我们在写LINQ的时候综合考虑这几个处理过程,应该对我们应对复杂的查询很有帮助。

 

作者:王清培

出处:http://www.cnblogs.com/wangiqngpei557/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

目录
相关文章
|
18天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
28天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
66 1
|
13天前
|
SQL API 数据库
Python中的SQLAlchemy框架:深度解析与实战应用
【4月更文挑战第13天】在Python的众多ORM(对象关系映射)框架中,SQLAlchemy以其功能强大、灵活性和易扩展性脱颖而出,成为许多开发者首选的数据库操作工具。本文将深入探讨SQLAlchemy的核心概念、功能特点以及实战应用,帮助读者更好地理解和使用这一框架。
|
14天前
|
机器学习/深度学习 分布式计算 BI
Flink实时流处理框架原理与应用:面试经验与必备知识点解析
【4月更文挑战第9天】本文详尽探讨了Flink实时流处理框架的原理,包括运行时架构、数据流模型、状态管理和容错机制、资源调度与优化以及与外部系统的集成。此外,还介绍了Flink在实时数据管道、分析、数仓与BI、机器学习等领域的应用实践。同时,文章提供了面试经验与常见问题解析,如Flink与其他系统的对比、实际项目挑战及解决方案,并展望了Flink的未来发展趋势。附带Java DataStream API代码样例,为学习和面试准备提供了实用素材。
37 0
|
1月前
|
开发框架 网络协议 .NET
深入.net框架
深入.net框架
11 0
|
1月前
|
Java 开发者
深入解析Java中的Lambda表达式
本文深入探讨Java编程语言中的Lambda表达式,介绍了Lambda表达式的定义、优势以及在实际开发中的应用场景,旨在帮助读者更好地理解和运用这一特性。
|
1月前
|
物联网 调度 开发者
构建高效Python Web应用:异步编程与Tornado框架解析
【2月更文挑战第27天】 在处理高并发的Web应用场景时,传统的同步阻塞模型往往难以满足性能需求。本文将深入探讨Python世界中的异步编程概念,并结合Tornado这一轻量级、非阻塞式Web服务器及框架,展示如何构建高性能的Web应用。通过实例驱动的方法论,我们将剖析Tornado的核心组件,包括其IOLoop、异步HTTP客户端和服务器端处理机制,以及与协程集成的细节。文章旨在为开发者提供一套实践指南,帮助他们利用Python实现快速响应和资源高效的Web服务。
31 2
|
1月前
|
算法 Java API
探索Java并发编程:Fork/Join框架的深度解析
【2月更文挑战第26天】随着多核处理器的普及,并发编程在软件开发中的重要性日益凸显。Java语言提供了多种并发工具,其中Fork/Join框架是处理分而治之问题的一个强大工具。本文将深入探讨Fork/Join框架的设计原理、使用场景及与传统线程池的区别,并通过实例演示如何有效利用该框架提升程序性能。
|
1月前
|
SQL API 数据处理
新一代实时数据集成框架 Flink CDC 3.0 —— 核心技术架构解析
本文整理自阿里云开源大数据平台吕宴全关于新一代实时数据集成框架 Flink CDC 3.0 的核心技术架构解析。
729 0
新一代实时数据集成框架 Flink CDC 3.0 —— 核心技术架构解析
|
1月前
|
监控 调度 开发者
构建高效Python Web应用:异步编程与Tornado框架深度解析
【2月更文挑战第20天】在处理高并发的Web应用时,传统的同步阻塞模型往往难以满足性能要求。本文将深入探讨Python异步编程的原理及其优势,并通过Tornado框架的案例分析,展示如何构建一个高效的异步Web服务。我们将从异步IO的基础讲起,逐步过渡到Tornado的核心组件,最终实现一个能够承载大量并发连接的Web服务器,为追求高性能Web解决方案的开发者提供实践指南。

推荐镜像

更多