APS.NET MVC + EF (01)---Linq和Lambda表达式
1.1 Linq介绍
LINQ全称 Language Integrated Query(语言集成查询)。为我们提供一种统一的方式来查询和操作各种数据。
- LINQ to Object:是针对实现了IEnumerable<T>的对象的LINQ;
- LINQ to SQL:是针对关系数据库的LINQ;
- LINQ to XML:是针对XML文档的LINQ。
LINQ除了提供一个统一的API来操作各种数据,并且为我们提供了编译时类型检查和动态创建查询表达式的能力。
LINQ查询时有两种语法可供选择:查询表达式语法(Query Expression)和方法语法(Fluent Syntax)。这两种方法是互补的。
1.1.1 查询表达式语法
基本语法:
from 变量 in 数据源对象 [where 条件] [group 变量 by 表达式 into 临时标识符] [orderby 表达式] select 选择列 |
示例1:
static void Main(string[] args) { int[] nums = { 10, 15, 20, 25, 30 }; // 从数组中查询所有偶数 var result = from n in nums where n % 2 == 0 select n; // 输出查询结果 foreach(int num in result) { Console.WriteLine(num); } } |
说明:
1、查询表达式语法与SQL(结构查询语言)语法相同。
2、查询语法必须以from子句开头,可以以Select或GroupBy子句结束 。
3、使用各种其他操作,如过滤,连接,分组,排序运算符以构造所需的结果。
4、隐式类型变量 - var可以用于保存LINQ查询的结果。
1.1.2 方法语法
方法语法(也称为流利语法)主要利用System.Linq.Enumerable类中定义的扩展方法和Lambda表达式方式进行查询。
例如示例1中的查询可以由以下方式代替,运行结果一致。
var result = nums.Where(n => n % 2 == 0); |
关于Lambda表达式的语法,我们在后面的内容中进行详细讲解。
1.1.3 查询表达式语法VS方法语法
查询表达式语法与方法语法存在着紧密的关系
1、CLR本身并不理解查询表达式语法,它只理解方法语法。
2、编译器负责在编译时将查询表达式语法翻译为方法语法。
3、大部分方法语法都有对应的查询表达式语法形式:如Select()对应select、OrderBy()对应orderby
4、部分查询方法目前在C#中还没有对应的查询语句:如Count()和Max()
1.2 Linq之查询语法
1.2.1 排序
用where子句找到感兴趣的数据后,Linq还可以方便的对得到的数据执行进一步处理,例如,给结果重新排序。下面的示例将以字母顺序给上一个查询的结果排序
示例2
static void Main(string[] args) { string[] names = { "alonso", "zheng", "smith", "jones", "smythe", "small", "Ruiz", "Hsieh", "Jorgenson", "Ilyich", "singh" }; var result = from n in names where n.StartsWith("s") orderby n select n; Console.WriteLine("以s开头的名字为:"); foreach (var item in result) { Console.WriteLine(item); } } |
示例说明:
- 这个程序与示例1几乎相同,只是在查询子句中增加了一行代码:
orderby n
即实现了对结果的排序功能。与where子句一样,orderby子句是可选的。
- Orderby子句默认为升序,但可以添加descending关键字,指定降序排列。如:
orderby n descending;
- 可以按照任意表达式进行排序,而无需重新编写查询。例如,要按照姓名中的最后一个字母顺序排序,只需添加如下子句:
orderby n.Substring(n.Length-1);
1.2.2 合计运算符
运算符 |
说明 |
Count() |
结果的个数 |
Min() |
结果中的最小值 |
Max() |
结果中的最大值 |
Average() |
数字结果的平均值 |
Sum() |
所有数字结果的和 |
示例3
class Program { static void Main(string[] args) { int[] numbers = CreateNumbers(12345); var result = from n in numbers where n > 1000 select n; 的个数为:" + result.Count()); 的最大数为:" + result.Max()); 的最小数为:" + result.Min()); 的平均数为:" + result.Average()); 的数的和为:" + result.Sum(n=>(long)n)); } private static int[] CreateNumbers(int count) { Random rand = new Random(0); int[] result = new int[count]; for (int i = 0; i < count; i++) { result[i] = rand.Next(); } return result; } } |
示例说明:
示例3中的Sum()方法传入了一个Lambda表达式n=>(long)n,以获得所有数字的和。这是Sum()方法的一个重载。由于和的结果太大,若个只是用Sum()会产生溢出。
1.2.3 查询复杂对象
示例4
// Student类 class Student { public int ID { get; set; } public string Name { get; set; } public string Sex { get; set; } public int Age{ get; set; } public int Class { get; set; } public override string ToString() { return "ID:" + ID + "\tName:" + Name + "\tSex:" + Sex + "\tAge:" + Age + "\tClass:" + Class; } } //main 方法 static void Main(string[] args) { List<Student> list = new List<Student>{ new Student{ID=1,Name="zhangsan",Sex="男", Age=18,Class=50}, new Student{ID=2,Name="lisi",Sex="男", Age=18,Class=50}, new Student{ID=3,Name="wuangwu",Sex="男", Age=20,Class=51}, new Student{ID=4,Name="zhaoliu",Sex="男", Age=20,Class=52}, new Student{ID=5,Name="zhouqi",Sex="女", Age=21,Class=52}, new Student{ID=6,Name="wangba",Sex="女", Age=20,Class=52} }; var result = from stu in list where stu.Age == 18 select stu; 的学员为:"); foreach (var stu in result) { Console.WriteLine(stu); } } |
1.2.4 投射:在查询中创建新对象
投射是在Linq查询中从其它数据类型中创建新数据类型的技术术语。Select关键字是投射运算符。
如Sql数据查询语言,select用来从数据表中选择适当的字段,在Linq中select与其类似。例如将示例4中的代码改为如下:
var result=from stu in list where stu.Age=18 select stu.Name; |
甚至可以通过给select添加表达式,来转换查询中的数据。如:
select stu.Name.ToUpper();
但是与sql不同,Linq不允许在select子句中有多个字段,即select stu.Name,stu.Age这样的形式将产生一个错误。如果要实现上述情况,需要在select子句中创建一个新对象,来保存查询的结果,如示例5所示。
示例5
//修改示例4Main方法 var result = from stu in list where stu.Age == 18 select new (stu.Name,stu.Age); 的学员为:"); foreach (var stu in result) { Console.WriteLine(stu); } |
1.2.5 多级排序
处理了带多个属性的对象后,要考虑按多种方式进行排序的问题了,例如我们先按照班级排序,在按照年龄排序。代码如下:
var result=from stu in list orderby stu.Class,stu.Age select stu;
还可以给字段添加Descending关键字。如
orderby stu.Class,stu.Age.deseending;
1.2.6 分组查询
在Linq中还可以实现像Sql中的Group by语句一样的分组统计功能。
示例6
var result=from stu in list group stu by stu.Class into student select new {Class=student.Key,Count=student.Count()}; var orderresult=from student in result orderby student.Count descending select student; |
在分组查询中的数据通过一个键(key)字段来分组,每个组中的所有程序都共享这个字段值,在此例中键字段是Class:
group stu by stu.Class
要计算每个组的数量,应该生成一个新的结果集student(可自定义):
group stu by stu.Class into student
1.2.7 Join查询
Join可以用一个查询搜索两个列表中相关的数据,用关键字段把结果连接起来。类似于SQL中join(内连接)操作。如:
var result = from stu in list join scr in Scores on stu.ID equals scr.ID select new { stu.ID, stu.Name, scr.score }; foreach (var ss in result) { Console.WriteLine(ss); } |
1.3 Linq之方法语法
1.3.1 Lambda表达式
Lambda表达式用来实现一个匿名方法,其语法为:
(参数列表)=> 语句或语句块
这是一个简单的Lambda表达式: (item)=>item<1000;
运算符 "=>"称为Lambda表达式。这个表达式定义了一个方法,其参数是item,如果item小于1000,该方法就返回ture,否则返回false。该方法是一个没有名称的匿名方法。
- 如果我们只有一个参数,我们也可以删除(),代码如下:
item=>item<1000;
- 如果需要传递多个参数,那么必须将参数括在括号内
(ints,item)=>ints.Contains(item);
- 在Lambda表达式中可以没有参数,如下所示:
( ) =>Console.WriteLine("这是一个不带参数的Lambda表达式");
- 如果正文表达式中有多条语句,那么必须用大括号将正文表达式括起来,如下所示:
(ints, item) => {
Console.WriteLine("这是包含多条语句的Lambda表达式");
return ints.Contains(item);
};
- Func委托
当需要指定Lambda表达式返回结果的类型时,可以使用Func<T,TResult>委托。如下所示:
Func<int[], bool> isContains= p=> p.Equals(10);
int[] ints= { 5 ,2 ,0, 66, 32, 7};
bool result=isContains(ints);
1.3.2 在Linq中使用Lambda表达式
回顾示例2中的代码:
var result = from n in names where n.StartsWith("s") select n;
我们可以用方法语法来实现:
var result = names.Where(n => n.StartsWith("s"));
我们发现,用法方法查询语法更加简洁。
- 过滤(筛选)
上面代码中Where()方法用来筛选,返回符合条件的子集。
- 排序(OrderBy、OrderByDescending、ThenBy、ThenByDescending)
对上面的查询结果排序可以使用如下语句。
var result = names.OrderBy(n => n).Where(n => n.StartsWith("s"));
或者
var result = names.Where(n => n.StartsWith("s")).OrderBy(n=>n);
方法调用的顺序不是固定的,只要Linq方法返回值为IEnumerable类型即可,可以按照容易理解的方式来使用。此规则适合于以后讲到的其他方法。
OrderBy()方法需要传入一个Lambda表达式用来告诉它用于排序的方法是什么,我们传送了最简单的Lambda表达式n=>n,因为只需要按照元素本身排序。还可以向上一章所讲那样按照最后一个字母进行排序:n=>n.Substring(n.Length-1)
为了给元素逆序排序,可以调用OrderByDescending()方法,使用方法和OrderBy()相同。
多级排序可以使用ThenBy()方法。例如:
var result=list.OrderBy(stu=>stu.Class) .ThenBy(stu=>stu.Age) .ThenBy(stu=>stu.Name) .Select(stu=>new {stu.Name,stu.Age,stu.Class}); |
多字段列表可以用在查询语法的OrderBy子句中。但在方法语法中第一项排序字段必须使用OrderBy()方法,随后使用ThenBy()方法。
如果第一个字段是以降序排序,需要使用OrderByDescending()方法,其他字段降序排序需要使用ThenByDescending()方法。
- 投射(Select)
Select()方法用于方法语法的投射。示例5的功能可以通过下面代码实现。
var result=list.Where(stu=>stu.Age==18)
.Select(stu=>new {stu.Name,stu.Age,stu.Class});
- Any 和 All
我们常常需要一类查询,确定数据是否满足某个条件,或者确保所有的数据都满足某个条件。例如,需要确定某个产品是否没有货了(库存为0)。
Linq提供了两个布尔方法:Any() 和 All(),它们可以快速确定对于数据而言,某个条件是true还是false。如下面示例所示:
bool anyStu = list.Any(stu => stu.Sex == "男"); if (anyStu) { Console.WriteLine("学员中有男同学"); } else { Console.WriteLine("学员中没有男同学"); } bool allStu = list.All(stu => stu.Sex == "男"); if (allStu) { Console.WriteLine("学员中全部是男同学"); } else { Console.WriteLine("学员中不全是男同学"); } |
- Take 和 Skip
Take()方法对应SQL语句中的Top运算符。与Take()方法相反的是Skip()方法,它可以跳过前n个结果,返回剩余的结果。例如:
var result = list.OrderBy(stu => stu.Age); Console.WriteLine("年龄最小的两名学员是:"); foreach (var stu in result.Take(2)) { Console.WriteLine(stu); } Console.WriteLine("其他学员依次为:"); foreach (var stu in result.Skip(2)) { Console.WriteLine(stu); } |
- First 和 FirstOrDefault
First()方法用来查找集合中第一个匹配的元素,如果没有找到匹配的结果则会引发一个异常。可以使用FirstOrDefault()方法避免异常的发生,若没有找到则返回有一个空。
示例代码:
Console.WriteLine("姓名为lisi的同学信息:"); Console.WriteLine(list.First(stu => stu.Name == "lisi")); Console.WriteLine("姓名为hanjiu的同学信息:"); Console.WriteLine(list.FirstOrDefault(stu => stu.Name == "hanjiu")); |
- Single和SingleOrDefault
相当于First()和FirstOrDefault(),但是如果不止一个匹配元素则抛出异常。
- 集合方法
Count:返回集合的个数。
Min/Max:返回集合的最小/大值。
Sum:返回集合元素的和。
Average:返回集合元素的平均值。
示例代码:
, , }; int fullCount = numbers .Count(); // 3 int digitCount = "pa55w0rd".Count(c => char.IsDigit(c)); // 3 int smallest = numbers.Min(); // 14; int largest = numbers.Max(); // 32; ); // 8; decimal sumTotal = numbers.Sum(); // 15 decimal average = numbers.Average(); // 5
|
本文只介绍了Linq的基本用法,尚有很多高级用法有待各位自行查阅资料进一步学习。
APS.NET MVC + EF (01)---Linq和Lambda表达式的更多相关文章
- c#封装DBHelper类 c# 图片加水印 (摘)C#生成随机数的三种方法 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象 c# 制作正方形图片 JavaScript 事件循环及异步原理(完全指北)
c#封装DBHelper类 public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> ...
- LInq 与lambda表达式
LInq 与lambda表达式 LinQ是我们常用的技术之一.因为我们绕不开的要对数据进行一系列的调整,如 排序. 条件筛选.求和.分组.多表联接 等等. lambda则是我们常用的语法糖,配合lin ...
- 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象
本文需要对C#里的LINQ.Lambda 表达式 .委托有一定了解. 在工作中,经常遇到需要对比两个集合的场景,如: 页面集合数据修改,需要保存到数据库 全量同步上游数据到本系统数据库 在这些场景中, ...
- SQL、Linq和Lambda表达式 的关系
首先说说这三者完全是三种不同的东西,SQL是结构化查询语言(Structured Query Language)简称,这大家再熟悉不过了,下面主要介绍LINQ和Lambda表达式的基本概念以及同一查询 ...
- 动态LINQ(Lambda表达式)构建
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; us ...
- APS.NET MVC + EF (02)---深入理解ADO.NET Entity Framework
2.7 深入理解Entity Framework 性能问题几乎是一切ORM框架的通病,对于EF来说,引起性能低的原因主要在以下几个方面. 复杂的对象管理机制为了在.NET中更好地管理模型对象,EF提供 ...
- APS.NET MVC + EF (07)---表单和HTML辅助方法
在ASP.NET MVC中,可以借助HtmlHelper 对象来输出页面内容,提高开发效率.下面,我们将介绍一些常用的辅助方法. 7.1 HTML辅助方法 BeginForm 该辅助方法主要用来产生& ...
- LINQ使用Lambda表达式选择几列
学习LINQ的Lambda的表达式,尝试从数据集合中,选择其中几列. 创建一个model: source code: namespace Insus.NET.Models { public class ...
- Linq之Lambda表达式
一 什么是LINQ? LINQ即Language Integrated Query(语言集成查询),LINQ是集成到C#和Visual Basic.NET这些语言中用于提供查询数据能力的一个新特性. ...
随机推荐
- maven仓库报错 sqljdbc4、ojdbc6、tomcat-jdbc-8.5.14
报错:Cannot resolve com.microsoft.sqlserver:sqljdbc4:4.0 和 Missing artifact com.microsoft.sqlserver: ...
- Codeforces E. High Load(构造)
题目描述: High Load time limit per test 2 seconds memory limit per test 512 megabytes input standard inp ...
- debug模式不报错,release模式报错
经常会 char * pMem = new char[icount]; 其中icount为变量,然后对该内存段猛的操作.release编译出来,出现莫名奇妙的错误.但是debug没问题. 后面查了别人 ...
- 2019牛客国庆day3-G &CF1238E
牛客G: 给定大小为N的数组a[],给定M组关系,让你重排a[],使得sum{M队关系的绝对值之差}最小.首先将a排序,然后依次把a填入数组. 假设i在二进制下有x个1,用dp[i]更新dp[i|(1 ...
- 线程三态和JVM线程状态
1.线程三态:就绪态.运行态.阻塞态 2.JVM中的六种状态 NEW(新建状态):一个尚未启动的线程所处的状态. RUNNABLE(可运行状态):可运行线程的线程状态,可能正在运行,也可能在等待处理器 ...
- cf1179D
cf1179D 链接 cf 思路 csdn 很玄学,正解是斜率优化dp,但被一个奇妙的贪心过了. 代码 #include <bits/stdc++.h> #define ll long l ...
- ERROR:Simulator861-Failed to link the design解决办法
在安装目录下找到collect2.exe文件,删除就可以解决了.D:\install_dir\ISE2\14.7\ISE_DS\ISE\gnu\MinGW\5.0.0\nt\libexec\gcc\m ...
- 第08组 Beta冲刺(2/5)
队名:955 组长博客:点这里! 作业博客:点这里! 组员情况 组员1(组长):庄锡荣 过去两天完成了哪些任务 文字/口头描述 ?按照时间进度的安排进行相应的检查 展示GitHub当日代码/文档签入记 ...
- [Gamma]Scrum Meeting#8
github 本次会议项目由PM召开,时间为6月3日晚上10点30分 时长15分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写博客,组织例会 撰写博客,组织例会 swoip 前端显示屏幕,翻译坐 ...
- 批处理中setlocal enabledelayedexpansion的作用详细整理
转自:https://www.jb51.net/article/29323.htm 设置本地为延迟扩展.其实也就是:延迟变量,全称延迟环境变量扩展, 想进阶,变量延迟是必过的一关!所以这一部分希望你能 ...