在开始了解LINQ to Entities之前,需要先对.NET Framework 3.5版本后对C#语言的几个扩展特性做一些阐释,这有助于我们更容易、更深刻的理解LINQ to Entities技术的原理与实现。

一、隐式实例化局部变量

.NET Framework 3.5后,实例化局部变量语法有了新的选择:使用“var”关键字隐式类型化:

var user = new User();

隐式类型化语法与Javascript语言里声明变量的语法类似,它可以一定程度上简化实例化局部变量的语法。但如果隐式实例化的作用仅限于此,那本文不会专门提及。隐式类型化更重要的用途是用于匿名类型的实例化。

需要提醒注意的是,只有局部变量实例化允许使用隐式实例化语法。这表示私有变量实例化无法享受该福利;同时,仅声明变量或实例化对象为null也是不允许使用隐式实例化语法的。

二、对象初始化

对象初始化指在实例化对象时,即可对对象的属性进行赋值:

1 var user = new User()
2 {
3 ID = Guid.NewGuid(),
4 Account = "Apollo"
5 };

三、匿名类型

LINQ to Entities的Select可以将实体类型投影为匿名类型,所以有必要对匿名类型作简单介绍。匿名类型指的是不显示声明类型的细节,而是根据上下文环境需要,临时声明满足需要的类型。由于该类型是临时需要的,所以不必为之命名。匿名类型的声明语法如下:

var user = new { ID = Guid.NewGuid(), Name = "Apollo" };

四、扩展方法

扩展方法是微软为扩展已有框架而创造的一个语法糖,.NET Framework 3.5就是通过很多扩展方法实现了对.NET Framework 2.0的升级扩展的。扩展方法很神奇,被扩展的对象可以不知道扩展方法的存在,就能在行为上得到扩展。扩展方法也很蹩脚,如果使用者不知情,很可能不知道对象具有扩展行为;抑或知道有扩展方法,但是不知道要引用哪个扩展库以使其支持扩展的行为。扩展方法的语法如下:

1 public static class UserExt
2 {
3 public static void Drink(this User user, object water)
4 {
5 …
6 }
7 }

五、Lambda表达式

Lambda表达式是由委托以及匿名方法发展而来的,它可将表达式或代码块(匿名方法)赋给一个变量,从而以最少量的输入实现编码目的。Lambda表达式一般配合IEnumerable<T>的静态扩展方法使用,完成对象集合的快捷查询操作。Lambda表达式的语法如下:

var user = db.Users.FirstOrDefault(o => o.Account == "Apollo");

六、标准查询操作符

System.Linq.Enumerable静态类声明了一套标准查询操作符(Standard Query Operators,SQO)方法集合。标准查询操作符的语法和标准SQL很相似,这不是偶然,而是微软有意为之,以使熟悉SQL的程序员们更容易上手。标准查询操作符的基本语法如下:

1 using (var db = new EntityContext())
2 {
3 var roles = from o in db.Users
4 where o.Account == "Apollo"
5 select o.Roles;
6 …
7 }

标准查询操作符和Lambda表达式的关系非常密切。编译器会将上诉表达式转化为下列以Lambda表达式为参数的显式扩展方法调用序列:

1 using (var db = new EntityContext())
2 {
3 var roles = db.Users.Where(o => o.Account == "Apollo").Select(o => o.Roles);
4 }

标准查询操作符

接下来,将针对数据查询操作中常用的条件查询、投影、分区、排序、分组、集合、元素、量词和聚集等标准查询操作符进行分类介绍。

一、条件操作符

条件操作符Where类似于SQL中的WHERE子句,用于实现条件查询。下列扩展方法表达式查询满足条件“角色不为空”的用户集合:

var user = db.Users.Where(o => o.Roles != null);

对应的标准查询操作符表达式为:

1 var users = from o in db.Users
2 where o.Roles != null
3 select o;

二、投影操作符

投影操作符Select类似于SQL中的SELECT子句,将对象投影为一个匿名类型实例,用于控制指定查询迭代器显示或者处理的对象属性。另外,需要注意的是,扩展方法表达式中的Select操作符并非必须的,省略模式下,会返回完整的被投影对象。下列扩展方法表达式将用户的帐号和密码信息投影为一个匿名类型:

var users = db.Users.Select(o => new { o.Account, o.Password });

对应的标准查询操作符表达式为:

1 var users = from o in db.Users
2 select new { o.Account, o.Password };

三、分区操作符

分区操作符实现对象的分区操作。其中,Take操作符类似于SQL中的TOP操作符,下列扩展方法表达式返回前5个用户对象:

var users = db.Users.OrderBy(o => o.Roles.Count).Take(5);

Skip操作符用于跳过指定个数对象并返回序列中的剩余对象,下列扩展方法表达式返回除前10个用户外的剩余用户:

var users = db.Users.OrderBy(o => o.Roles.Count).Skip(10);

TakeWhile操作符用于返回条件表达式值为真时的相邻元素集合,下列扩展方法表达式返回第一个拥有3个角色的用户之前的所有用户集合:

var users = db.Users.OrderBy(o => o.Roles.Count).TakeWhile(o => o.Roles.Count == 3);

SkipWhile操作符用于跳过条件表达式值为真时的元素,并返回剩下的元素集合,下列扩展方法表达式返回第一个拥有3个角色的用户之后的所有用户集合:

var users = db.Users.OrderBy(o => o.Roles.Count).SkipWhile(o => o.Roles == 3);

四、排序操作符

排序操作符实现对象的排序功能,包括OrderBy、OrderByDescending、ThenBy、ThenByDescending和Reverse五个操作符。其中OrderBy操作符实现对象的升序排列,相当于SQL中的ORDER BY ASC子句,下列扩展方法表达式实现用户按拥有的角色数进行升序排列:

var users = db.Users.OrderBy(o => o.Roles.Count);

对应的标准查询操作符表达式为:

1 var users = from o in db.Users
2 orderby o.Roles.Count
3 select o;

OrderByDescending操作符实现对象的降序排列,相当于SQL中的ORDER BY DESC子句,下列扩展方法表达式实现用户按拥有的角色数进行降序排列:

var users = db.Users.OrderByDescending(o => o.Roles.Count);

对应的标准查询操作符表达式为:

1 var users = from o in db.Users
2 orderby o.Roles.Count descending
3 select o;

ThenBy、ThenByDescending和Reverse操作符只能针对IOrderedEnumerable接口对象使用,所以一般紧跟在OrderBy/OrderByDesending操作符方法后使用。ThenBy操作符由编译器翻译为对OrderBy操作符的再次调用;ThenByDescending操作符由编译器翻译为对OrderByDescending操作符的再次调用;Reverse操作符实现对象的排序反向。这里不再一一举例。

五、分组操作符

分组操作符GroupBy类似于SQL中的GROUP BY子句,实现对象的分组操作。下列扩展方法表达式实现用户对象按拥有的角色数量进行分组:

var users = db.Users.GroupBy(o => o.Roles.Count);

对应的标准查询操作符表达式为:

1 var users = from o in db.Users
2 group o by o.Roles.Count into g
3 select new { RoleCount = g.Key, Group = g };

六、集合操作符

集合操作符包括Distinct、Union、intersect和Except四个操作符,除Distinct外,其他三个操作符都可将两个序列组合成一个序列。Distinct操作符类似于SQL中的DISTINCT关键字,用于删除序列中具有重复值的对象。下列扩展方法表达式实现将用户角色中的重复角色删除功能:

var roles = user.Roles.Distinct();

Union操作符类似于SQL中的UNION关键字,用于求具有同样结构的两个序列的并集。下列扩展方法表达式实现将用户1和用户2所拥有的角色组合成一个角色集合,并排除其中重复的角色:

var roles = user1.Roles.Union(user2.Roles);

Intersect操作符类似于SQL中的INTERSECT关键字,用于求具有同样结构的两个序列的交集。下列扩展方法表达式返回用户1和用户2都具有的角色集合:

var roles = user1.Roles.Intersect(user2.Roles);

Except操作符类似于SQL中的EXCEPT关键字,用于返回第一个序列中有、但第二个序列中没有的对象集合。下列扩展方法表达式返回用户1拥有,而用户2没有的角色集合:

var roles = user1.Roles.Except(user2.Roles);

七、元素操作符

元素操作符包括两组操作符,分别是用于从一个IEnumerable<T>序列中返回满足条件的单个对象或无满足条件对象时抛异常的First、Last和Single操作符,以及返回满足条件的单个对象或无满足条件对象时返回空对象的FirstOrDefault、LastOrDefault和SingleOrDefault操作符。其中First和FirstOrDefault操作符用于返回第一个满足条件的对象。下列扩展方法表达式返回第一个拥有三个角色的用户:

var user = db.Users.FirstOrDefault(o => o.Roles.Count == 3);

Last和LastOrDefault操作符用于返回最后一个满足条件的对象。下列扩展方法表达式返回最后一个拥有三个角色的用户:

var user = db.Users.LastOrDefault(o => o.Roles.Count == 3);

Single和SingleOrDefault操作符用于返回满足条件的序列中的唯一元素,如果序列中包含不止一个元素,将会抛异常。下列扩展方法表达式返回帐号为“Apollo”的唯一用户,如果有多个用户帐号都为“Apollo”,则抛异常:

var user = db.Users.SingleOrDefault(o => o.Account == "Apollo");

八、量词操作符

量词操作符包括 Any、All和Contains三个操作符,用于检查序列中是否有一些对象或所有对象满足条件。其中,Any操作符用于检查序列中是否有任何一个对象满足条件。下列扩展方法表达式当有任何一个用户拥有三个角色时返回真,否则返回假:

var result = db.Users.Any(o => o.Roles.Count == 3);

All操作符用于检查序列中是否所有对象均满足条件。下列扩展方法表达式当所有用户均拥有三个角色时返回真,否则返回假:

var result = db.Users.All(o => o.Roles.Count == 3);

Contains操作符用于检查序列中是否包含指定的对象。下列扩展方法表达式当集合中包含用户1则返回真,否则返回假:

var result = db.Users.Where(o => o.Roles.Count == 3).Contains(user1);

九、聚集操作符

聚集操作符包括Count、Min、Max、Sum和Average等多个操作符,用于对对象集合进行统计计算。其中,Count操作符类似于SQL中的COUNT关键字,用于计算序列中满足条件的对象个数。下列扩展方法表达式返回拥有3个角色的用户数量:

var result = db.Users.Count(o => o.Roles.Count == 3);

Min操作符类似于SQL中的MIN关键字,用于返回按条件计算的最小值。下列扩展方法表达式返回拥有最少角色数量的用户所拥有的角色数量:

var result = db.Users.Min(o => o.Roles.Count);

Max操作符类似于SQL中的MAX关键字,用于返回按条件计算的最大值。下列扩展方法表达式返回拥有角色数量最多的用户所拥有的角色数量:

var result = db.Users.Max(o => o.Roles.Count);

Sum操作符类似于SQL中的SUM关键字,用于返回按条件计算的总数。下列扩展方法表达式返回已赋予用户的所有角色总数:

var result = db.Users.Sum(o => o.Roles.Count);

Average操作符类似于SQL中的AVERAGE关键字,用于返回按条件计算的平均值。下列扩展方法表达式,用于返回用户所拥有的角色平均数:

var result = db.Users.Average(o => o.Roles.Count);

总结

本文首先给出了LINQ技术的官方实现集合,以及LINQ to Entities实现的技术细节;然后概要介绍了与LINQ to Entities相关的几个基本概念;最后对LINQ to Entities常用的标准查询操作符的使用进行了分类介绍,从中也可以看出LINQ to Entities和SQL的功能基本是一一对应的。

LINQ to Entity Framework 操作符(转)的更多相关文章

  1. 【转】Entity Framework技术系列之7:LINQ to Entities

    前言 LINQ(Language Integrated Query,语言集成查询)是一组用于C#和VB.NET语言的扩展,它允许编写C#或者VB.NET代码,以与查询数据库相同的方式操作内存数据. L ...

  2. Entity Framework学习笔记(五)----Linq查询(2)---贪婪加载

    请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,我们使用了Linq对Entity Framework进行了一个查询,但是通过学习我们却发现了懒加载给我来的性能上的 ...

  3. 浅析Entity Framework Core2.0的日志记录与动态查询条件

    前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework Core2.0的日志记录与动态查询条件 去 ...

  4. Entity Framework Core 2.0 中使用LIKE 操作符

    Entity Framework Core 2.0 中使用LIKE 操作符 不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译 ...

  5. 《Entity Framework 6 Recipes》中文翻译系列 (26) ------ 第五章 加载实体和导航属性之延缓加载关联实体和在别的LINQ查询操作中使用Include()方法

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-7  在别的LINQ查询操作中使用Include()方法 问题 你有一个LINQ ...

  6. LINQ之路10:LINQ to SQL 和 Entity Framework(下)

    在本篇中,我们将接着上一篇“LINQ to SQL 和 Entity Framework(上)”的内容,继续使用LINQ to SQL和Entity Framework来实践“解释查询”,学习这些技术 ...

  7. LINQ之路 9:LINQ to SQL 和 Entity Framework(上)

    在上一篇中,我们从理论和概念上详细的了解了LINQ的第二种架构“解释查询”.在这接下来的二个篇章中,我们将使用LINQ to SQL和Entity Framework来实践“解释查询”,学习这些技术的 ...

  8. Entity Framework 5中应用表值函数进行Linq查询

    Entity Framework 5引入了表值函数(Table-Valued Functions TVFs).表值函数的返回类型是一个Table类型,可用在SQL查询语句中.最简单的表值函数,读取客户 ...

  9. EF(Entity Framework)多对多关系下用LINQ实现"NOT IN"查询

    这是今天在实际开发中遇到的一个问题,需求是查询未分类的博文列表(未加入任何分类的博文),之前是通过存储过程实现的,今天用EF实现了,在这篇博文中记录一下. 博文的实体类BlogPost是这样定义的: ...

随机推荐

  1. where can I find source of com.android.internal.R.styleable.AlertDialog_multiChoiceItemLayout?

    I want to modify Alert dialog multi select layout. For my program I want two line multi-select item. ...

  2. python单/双下划线使用

    在Python编程中经常会遇到函数(function),方法(method)及属性(attribute)以下划线'_'作为前缀,这里做个总结. 主要存在四种情形: 1. object # public ...

  3. ASP.NET动态引用WebService接口

    尊重原著作:本文转载自http://www.mhzg.net/a/20124/20124912180589.html 有经验的朋友都知道,通常我们在引用webservice的时候,是在项目中就添加了引 ...

  4. EBS-利用form个性化 调用报表【Z】

    1.在工具中添加调用报表的功能 条件: 触发器事件:WHEN-NEW-FORM-INSTANCE 活动: 类型为:菜单 菜单项:specialn n为1..6 菜单标签:打印xx报表 2.对speci ...

  5. eclipse中输入的中文为繁体的问题

    今天在eclipse中编写注释的时候发现,输入的中文都为繁体,且只在eclipse编辑器中为繁体,切换到网页中则为正常. 最后发现,竟然是输入法的shift+ctrl+F快捷键和eclipse的冲突. ...

  6. sql 设计反模式

    ---恢复内容开始--- 1.乱穿马路 ---- > 目标 : 存储多值属性. 1) 错误方法: 使用格式化的逗号分割列表. 1-> 不适合查询,定位数据,无法运用聚合函数进行分组,不利于 ...

  7. nginx+php-fpm json_encode 到client pages 截断

    同样的数据rd环境is normal, but in test environment the result of json had been intercepted 稳定定位: nginx指定的磁盘 ...

  8. Android GridView 二维布局界面

    GridView用于在界面上按行.列分布的方式来显示多个组件. <LinearLayout xmlns:android="http://schemas.android.com/apk/ ...

  9. android sdk 更新问题——截止2014年6月10日有效

    因为墙的原因,很多人的sdk都更新不了,下面记录了我刚刚实现更新的方法: 进到Android SDK Manager,菜单Tools->Options..,这时弹出一个框,在这个框的下面Othe ...

  10. wifi相关协议

    IEEE 802.11Wi-Fi 协议摘要 协议 频率 信号 最大,数据率 传统802.11 2.4GHz FHSS或DSSS 2Mbps 802.11a 5GHz OFDM 54Mbps 802.1 ...