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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:

在看本篇文章之前我假设您已经具备我之前分析的一些原理知识,因为这章所要讲的内容是建立在之前的一系列知识点之上的,为了保证您的阅读顺利建议您先阅读本人的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:

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:

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:

3

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

由于Where方法里面的Lambda表达如果被执行的话,那么将不会执行(truck.LICENSE-NUMBER.Length<10),所以这点为我们的多条件拼接提供了接口。[王清培版权所有,转载请给出署名]

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

4

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

public List<Truck> GetList(Truck truckModel) 

    using (KJtest0817Entities DbContext = new KJtest0817Entities()) 
    { 
        var resultList = from truck in DbContext.TB_CX_TRUCK 
                         where string.IsNullOrEmpty(truckModel.ENGINE_NUMBER) || truck.ENGINE_NUMBER == truckModel.ENGINE_NUMBER 
                         where string.IsNullOrEmpty(truckModel.LICENSE_NUMBER) || truck.ENGINE_NUMBER == truckModel.LICENSE_NUMBER 
                         select new Truck() 
                         { 
                             BRAND = truck.BRAND 
                         }; 
        return resultList.ToList(); 
    } 
}

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

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

如果有很多个查询条件,那么我们将要写很多这样的判断代码,即不方便也不美观。[王清培版权所有,转载请给出署名]

 5

多条件之间的OR查询

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

public List<DutyModel> GetList(DutyModel dutyModel) 

    using (UserOrgDemo2Entities Context = new UserOrgDemo2Entities()) 
    { 
        IQueryable<TB_DUTY> result = Context.TB_DUTY.AsQueryable(); 
        System.Linq.Expressions.Expression<Func<TB_DUTY, bool>> expressionDUTY = DynamicLinqExpressions.True<TB_DUTY>();

        if (!(dutyModel.RANK_NO == 0)) 
            expressionDUTY.Or(duty => duty.RANK_NO == dutyModel.RANK_NO); 
        if (!string.IsNullOrEmpty(dutyModel.USER_PRIV)) 
            expressionDUTY.Or(duty => duty.USER_PRIV == dutyModel.USER_PRIV);

       return result.Where(expressionDUTY).Select(tb_duty=>new DutyModel(){ USER_PRIV=tb_duty.USER_PRIV}).ToList(); 
    } 
}

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

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

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




 本文转自 王清培 51CTO博客,原文链接:http://blog.51cto.com/wangqingpei557/1132182,如需转载请自行联系原作者



相关文章
|
28天前
|
前端开发 JavaScript C#
移动应用开发中的跨平台框架解析
【9月更文挑战第5天】在移动应用开发领域,跨平台框架因其“一次编写,处处运行”的便利性而受到开发者的青睐。本文将深入探讨几种流行的跨平台框架,包括React Native、Flutter和Xamarin,并比较它们的优势与局限。我们将通过代码示例揭示这些框架如何简化移动应用的开发过程,同时保持高性能和良好的用户体验。无论你是新手还是有经验的开发者,这篇文章都将成为你了解和选择跨平台框架的宝贵资源。
50 19
|
28天前
|
监控 网络协议 API
.NET WebSocket 技术深入解析,你学会了吗?
【9月更文挑战第4天】WebSocket 作为一种全双工协议,凭借低延迟和高性能特点,成为实时应用的首选技术。.NET 框架提供了强大的 WebSocket 支持,使实时通信变得简单。本文介绍 WebSocket 的基本概念、.NET 中的使用方法及编程模型,并探讨其在实时聊天、监控、在线游戏和协同编辑等场景的应用,同时分享最佳实践,帮助开发者构建高效实时应用。
77 12
|
27天前
|
Linux C# Android开发
一个开源、跨平台的.NET UI框架 - Avalonia UI
一个开源、跨平台的.NET UI框架 - Avalonia UI
|
27天前
|
机器学习/深度学习 人工智能 算法
ML.NET:一个.NET开源、免费、跨平台的机器学习框架
ML.NET:一个.NET开源、免费、跨平台的机器学习框架
|
27天前
|
消息中间件 开发框架 前端开发
YuebonCore:基于.NET8开源、免费的权限管理及快速开发框架
YuebonCore:基于.NET8开源、免费的权限管理及快速开发框架
|
27天前
|
JSON 测试技术 C#
C#/.NET/.NET Core优秀项目框架推荐榜单
C#/.NET/.NET Core优秀项目框架推荐榜单
|
2月前
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
72 0
|
2月前
|
API 开发者 Java
API 版本控制不再难!Spring 框架带你玩转多样化的版本管理策略,轻松应对升级挑战!
【8月更文挑战第31天】在开发RESTful服务时,为解决向后兼容性问题,常需进行API版本控制。本文以Spring框架为例,探讨四种版本控制策略:URL版本控制、请求头版本控制、查询参数版本控制及媒体类型版本控制,并提供示例代码。此外,还介绍了通过自定义注解与过滤器实现更灵活的版本控制方案,帮助开发者根据项目需求选择最适合的方法,确保API演化的管理和客户端使用的稳定与兼容。
70 0
|
2月前
|
开发者 C# Android开发
Xamarin 与 .NET:解锁现代化移动应用开发的超级武器——深入探讨C#与.NET框架如何赋能跨平台应用,实现高效编码与卓越性能
【8月更文挑战第31天】Xamarin 与 .NET 的结合为开发者提供了强大的平台,用于构建现代化移动应用。通过 C# 和 .NET 框架,Xamarin 可以实现一次编写、多平台运行,覆盖 iOS、Android 和 Windows。这种方式不仅节省了开发时间和成本,还保证了应用的一致性和高质量。Xamarin 是一个开源框架,专为跨平台移动应用开发设计,允许使用 C# 语言和 .NET 核心库构建原生应用,并访问各平台特定功能。微软维护的 Xamarin 是 Visual Studio 生态系统的一部分,极大地提高了开发效率。
61 0
|
2月前
|
Web App开发 IDE 测试技术
自动化测试的利器:Selenium 框架深度解析
【8月更文挑战第31天】在软件开发的世界中,自动化测试是提高产品质量和开发效率不可或缺的一环。本文将深入探讨Selenium这一强大的自动化测试工具,从其架构、优势到实战应用,一步步揭示如何利用Selenium框架提升软件测试的效率和准确性。通过具体的代码示例,我们将展示Selenium如何简化测试流程,帮助开发者快速定位问题,确保软件的稳定性和可靠性。无论你是测试新手还是资深开发者,这篇文章都将为你打开一扇通往高效自动化测试的大门。

推荐镜像

更多
下一篇
无影云桌面