一、什么是LINQ

长期以来,开发社区形成以下的格局:

1、面向对象与数据访问两个领域长期分裂,各自为政。

2、编程语言中的数据类型与数据库中的数据类型形成两套不同的体系,例如:

  C#中字符串用string数据类型表示。

  SQL中字符串用NVarchar/Varchar/Char数据类型表示。

3、SQL编码体验落后

  没有智能感知效果。

  没有严格意义上的强类型和类型检查。

4、SQL和XML都有各自的查询语言,而对象没有自己的查询语言。

上面描述的问题,都可以使用LINQ解决,那么究竟什么是LINQ呢?

LINQ(Language Integrated Query)即语言集成查询。

LINQ是一组语言特性和API,使得你可以使用统一的方式编写各种查询。用于保存和检索来自不同数据源的数据,从而消除了编程语言和数据库之间的不匹配,以及为不同类型的数据源提供单个查询接口。

LINQ总是使用对象,因此你可以使用相同的查询语法来查询和转换XML、对象集合、SQL数据库、ADO.NET数据集以及任何其他可用的LINQ提供程序格式的数据。

LINQ主要包含以下三部分:

1、LINQ to Objects      主要负责对象的查询。

2、LINQ to XML           主要负责XML的查询。

3、LINQ to ADO.NET   主要负责数据库的查询。

  LINQ to SQL

  LINQ to DataSet

  LINQ to Entities

LINQ教程二:LINQ操作语法

LINQ查询时有两种语法可供选择:查询表达式语法(Query Expression)和方法语法(Fluent Syntax)。

一、查询表达式语法

查询表达式语法是一种更接近SQL语法的查询方式。

LINQ查询表达式语法如下:

1 from<range variable> in <IEnumerable<T> or IQueryable<T> Collection>
2 <Standard Query Operators> <lambda expression>
3 <select or groupBy operator> <result formation>

LINQ查询表达式

约束 LINQ查询表达式必须以from子句开头,以select或group子句介绍
关键字 功能
from....in...

指定要查询的数据源以及范围变量,多个from子句则表示从多个数据源查找数据。注意:C#编译器会把“复合from子句”的查询表达式转换为SelectMany()扩展方法。

join…in…on…equals… 指定多个数据源的关联方式
let 引入用于存储查询表达式中子表达式结果的范围变量。通常能达到层次感会更好,使代码更易于阅读。
orderby、descending 指定元素的排序字段和排序方式。当有多个排序字段时,由字段顺序确定主次关系,可指定升序和降序两种排序方式
where 指定元素的筛选条件。多个where子句则表示了并列条件,必须全部都满足才能入选。每个where子句可以使用谓词&&、||连接多个条件表达式。
group 指定元素的分组字段。
select 指定查询要返回的目标数据,可以指定任何类型,甚至是匿名类型。(目前通常被指定为匿名类型)
into

提供一个临时的标识符。该标识可以引用join、group和select子句的结果。

1)        直接出现在join子句之后的into关键字会被翻译为GroupJoin。(into之前的查询变量可以继续使用)

2)        select或group子句之后的into它会重新开始一个查询,让我们可以继续引入where, orderby和select子句,它是对分步构建查询表达式的一种简写方式。(into之前的查询变量都不可再使用)

查询语法从一个From子句开始,然后是一个Range变量。 From子句的结构类似于“From rangeVariableName in
IEnumerablecollection”。 在英语中,这意味着,从集合中的每个对象。
它类似于foreach循环:foreach(student in studentList)。

在From子句之后,您可以使用不同的标准查询运算符来过滤,分组,连接集合的元素。 LINQ中有大约50个标准查询运算符。标准查询运算符后面通常跟一个条件,这个条件通常使用lambda表达式来表示。

LINQ查询语法总是以Select或Group子句结束。 Select子句用于对数据进行整形。 您可以选择整个对象,因为它是或只有它的一些属性。 在上面的例子中,我们选择了每个结果字符串元素。

例如:我们要从数组中查询出偶数,查询表达式示例代码如下:

var result = from p in ints where p % 2 == 0 select p;

查询表达式语法要点总结:

1、查询表达式语法与SQL(结构查询语言)语法相同。

2、查询语法必须以from子句开头,可以以Select或GroupBy子句结束 。

3、使用各种其他操作,如过滤,连接,分组,排序运算符以构造所需的结果。

4、隐式类型变量 - var可以用于保存LINQ查询的结果。

二、方法语法

方法语法(也称为流利语法)主要利用System.Linq.Enumerable类中定义的扩展方法和Lambda表达式方式进行查询,类似于如何调用任何类的扩展方法。

以下是一个示例LINQ方法语法的查询,返回数组中的偶数:

var result = ints.Where(p => p % 2 == 0).ToArray();

从上面的示例代码中可以看出:方法语法包括扩展方法和Lambda表达式。 扩展方法Where()在Enumerable类中定义。

如果你检查Where扩展方法的签名,你会发现Where方法接受一个谓词委托,如Func <Student,bool>。 这意味着您可以传递任何接受Student对象作为输入参数的委托函数,并返回一个布尔值,如下图所示。 lambda表达式作为在Where子句中传递的委托传递。 在下一节中学习lambda表达式。

三、查询表达式语法VS方法语法

查询表达式语法与方法语法存在着紧密的关系
1、CLR本身并不理解查询表达式语法,它只理解方法语法。
2、编译器负责在编译时将查询表达式语法翻译为方法语法。
3、大部分方法语法都有对应的查询表达式语法形式:如Select()对应select、OrderBy()对应orderby
4、部分查询方法目前在C#中还没有对应的查询语句:如Count()和Max(),这是只能采用以下替代方案:
  方法语法
  查询表达式语法+方法语法的混合方式

LINQ教程三:Lambda表达式解剖

C#3.0(.NET3.5)中引入了Lambda表达式和LINQ。Lambda表达式是使用一些特殊语法表示匿名方法的较短方法。

最基本的Lambda表达式语法如下:

(参数列表)=>{方法体}

说明:

1、参数列表中的参数类型可以是明确类型或者推断类型。

2、如果是推断类型,则参数的数据类型将由编辑器根据上下文自动推断出来。

让我们看看Lambda表达式是如何从匿名方法演变而来的。

相关示例:

1 delegate(int item) { return item % 2 == 0; };

1、Lambda表达式从匿名方法演变,首先删除delegate关键字和参数类型并添加Lambda运算符=>,演变后的代码如下:

1 (item)=>{return item % 2 == 0;};

2、如果我们只有一个返回值的语句,那么我们不需要花括号、返回和分号,所以我们可以去掉这些符号,演变后的代码如下:

1 (item)=>item %2 == 0;

3、如果我们只有一个参数,我们也可以删除(),代码如下:

1 item=>item %2 == 0;

因此,我们得到如下所示的Lambda表达式:

item => item % 2 == 0

其中item是参数,=>是Lambda运算符,item % 2 == 0是正文表达式。

二、具有多个参数的Lambda表达式

如果需要传递多个参数,那么必须将参数括在括号内,如下所示:

1 (ints, item) => ints.Contains(item);

如果不想使用推断类型,那么可以给出每个参数的类型,如下所示:

1 (int[] ints, int item) => ints.Contains(item)

三、不带任何参数的Lambda表达式

在Lambda表达式中可以没有参数,如下所示:

1 () => Console.WriteLine("这是一个不带任何参数的Lambda表达式");

四、正文表达式中有多条语句

在前面讲过,如果正文表达式有一个语句,那么可以去掉方法体外面的大括号。如果正文表达式中有多条语句,那么必须用大括号将正文表达式括起来,如下所示:

(ints, item) =>
{
Console.WriteLine("这是包含多条语句的Lambda表达式");
return ints.Contains(item);
};

五、表达式中的局部变量

你可以在表达式的主体中声明一个变量,以便在表达式主体的任何位置使用它,如下所示:

1 ints =>
2 {
3 int item = 10;
4 return ints.Contains(item);
5 };

六、Lambda表达式中的内置泛型委托

1、Func委托

当你想从lambda表达式返回一些东西时,使用Func <> delegate。

其中T是输入参数的类型,TResult是返回类型。

示例代码如下:

1 Func<int[], bool> isContains = p => p.Equals(10);
2 int[] ints = { 5, 2, 0, 66, 4, 32, 7, 1 };
3 bool isEquals = isContains(ints);

在上面的例子中,Func委托期望第一个输入参数是int[]类型,返回类型是boolean。Lambda表达式是p => p.Equals(10)。

2、Action委托

与Func委托不同,Action委托只能有输入参数。 当不需要从lambda表达式返回任何值时,请使用Action委托类型。

示例代码如下:

1 Action<int[]> PrintItem = p =>
2 {
3 foreach (int item in p)
4 {
5 Console.WriteLine(item);
6 }
7 };
8 int[] ints = { 5, 2, 0, 66, 4, 32, 7, 1 };
9 PrintItem(ints);

七、在LINQ中使用Lambda表达式

通常情况下,Lambda表达式与LINQ查询一起使用。枚举静态类包括接受Func <TSource,bool>的IEnumerable <T>的Where扩展方法。IEnumerable <Int>集合的Where()扩展方法需要传递Func <Student,bool>,如下所示:

现在,您可以将分配给Func委托的lambda表达式传递给方法语法中的Where()扩展方法,如下所示:

1 Func<int, bool> isContains = p =>p.Equals (4);
2 int[] ints = { 5, 2, 0, 66, 4, 32, 7, 1 };
3 var result = ints.Where(isContains).ToList();

八、Lambda表达式要点总结

1、Lambda表达式是一种表示匿名方法的更短的方法。

2、Lambda表达式语法:parameters =>正文表达式

3、Lambda表达式可以在()中具有零个或多个参数。

4、Lambda表达式可以在大括号{}中的正文表达式中有一条或多条语句。

5、Lambda表达式可以分配给Func,Action或Predicate委托。

6、Lambda表达式可以以类似的方式调用委托。

四  实例操作

一、什么是LINQ

LINQ是Language Integrate Query的缩写,意为语言集成查询,是微软在.Net Framework 4.5版中推出的主要特性之一。

它为开发人员提供了统一的数据查询模式,并与.Net开发语言(如C#和VB.Net)集成,很大程度上简化了数据查询的编码和调试工作,提供了数据查询的性能。

LINQ中查询表达式访问的是一个对象,而该对象可以表示为各种类型的数据源。比如SQL Server数据库,XML文档,ADO.NET数据集,以及内存中的数据集合等。

在.NET类库中,LINQ相关类库都在System.Linq命名空间中,该命名空间提供支持使用LINQ进行查询的类和接口,其中主要是以下两个接口和两个类:

IEnumerable<T>接口:它表示可以查询的数据集合,一个查询通常是逐个对集合对象中的元素进行筛选操作,返回一个新的IEnumerable<T>对象,用来保存查询结果。

IQueryable<T>接口:它继承自IEnumerable<T>接口,表示一个可以查询的表达式目录树。

Enumerable类:它通过对IEnumerable<T>提供扩展方法,实现LINQ标准查询运算。包括过滤、导航、排序、关联、求和、求最大值、求最小值等操作。

Queryable类:它通过对IQueryable<T>提供扩展方法,实现LINQ标准查询运算。包括过滤、导航、排序、关联、求和、求最大值、求最小值等操作。

根据数据源类型,可以将LINQ技术分为以下几个主要技术方向:

1.LINQ to Object:数据源为实现了接口IEnumerable<T>和IQueryable<T>的内存数据集合,这也是LINQ的基础,本文将介绍着方面的内容。

2.LINQ to ADO.NET:数据源为ADO.NET数据集,这里将数据库中的表结构映射到类结构,并通过ADO.NET从数据库中获取数据集到内存,通过LINQ进行数据查询。

3.LINQ to XML:数据源为XML文档,这里通过XElement、XAttribute等类将XML文档数据加载到内存中,通过LINQ进行数据查询。

二、LINQ查询表达式

在进行LINQ查询的编写之前,首先要了解查询表达式。查询表达式是LINQ查询的基础,也是最常用的编写LINQ查询的方法。查询表达式由查询关键字和对应的操作数组成。其中,查询关键字是常用的查询运算符。

在C# 3.0中可以直接使用的查询关键字和功能如下表:

1.用from子句指定数据源

每个LINQ查询表达式都以from子句开始,from子句包括以下两个功能。

(1)指定查询将采用的数据源

(2)定义一个本地变量,表示数据源中单个数据

单个from子句的编写格式为: from localVar in dataSource,其中,dataSource表示数据源,localVar表示单个元素。

示例代码如下:

            int[] array = { 1, 2, 4, 5, 7 };
var query = from item in array
select item;
foreach (var item in query)
{
Console.WriteLine(item);
}

2.使用select子句指定目标数据源

select子句指定在执行查询是产生的结果类型,其格式为:select element,其中elment参数指定查询结果中元素的类型及初始化方式。

在进一步介绍select子句之前,先介绍一下本文示例中要用到的实体类:

public class LessonScore
{
/// <summary>
/// 课程成绩
/// </summary>
public float Score { get; set; }
/// <summary>
/// 课程名称
/// </summary>
public string Lession { get; set; } public override string ToString()
{
return string.Format("{0}-----{1}分",Lession,Score);
}
} public class Student
{
/// <summary>
/// 学生名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 学生性别
/// </summary>
public string XingBie { get; set; }
/// <summary>
/// 学生年龄
/// </summary>
public int Age { get; set; } public List<LessonScore> Scores { get; set; } public override string ToString()
{
 return string.Format("{0}---{1}---{2}",Name, XingBie,Age);
}
}

select子句中要选择的目标类型不仅可以为数据源中的元素,还可以是该元素的不同操作结果,包括属性、方法和运算等。示例代码如下:

              Student[] students = {
new Student() {Name="乔峰",Age=20,XingBie="男" },
new Student() {Name="欧阳修",Age=22,XingBie="男" },
new Student() {Name="王五",Age=19,XingBie="男" },
new Student() {Name="王丹",Age=20,XingBie="女" },
new Student() {Name="倾国倾城",Age=18,XingBie="女" }
};
var query1 = from student in students
select student;//整个元素作为查询结果
foreach (var item in query1)
{
Console.WriteLine(item);
} var query2 = from student in students
select student.Name;//元素的属性作为查询结果
foreach (var item in query2)
{
Console.WriteLine(item);
} var query3 = from student in students
select student.Name.Length;
foreach (var item in query3)
{
Console.WriteLine(item);
}

在某些特殊的场合下,往往查询结果只是临时使用一下,而查询结果的数据包括很多字段,并非一个简单的属性、方法返回值等。这时,可在select子句中使用匿名类型来解决这类问题。

示例代码如下:

                //返回数据源中学生的姓名、年龄、姓名的长度
//使用匿名类型方式返回
var query4 = from student in students
select new {student.Name,student.Age,NameLen = student.Name.Length };
foreach (var item in query4)
{
Console.WriteLine(item);
}

3.使用where子句指定筛选条件

通常一个LING查询不会如前面的示例代码那么简单,通常还需要对数据源中的元素进行过滤。只有符合条件的元素,才能参与查询结果的计算。

LINQ中,where子句格式为:where expression,其中,expression是一个逻辑表达式,返回布尔值。

where子句中的条件表达式,可以用&&和||指定多个条件的逻辑运算关系。其中,&&表示逻辑并,||表示逻辑或。

示例代码:

                int[] array = { 1,3,9,5,16,20,54,60,18,37};
var query1 = from item in array //查询array中所以大于15的元素
where item > 15
select item; foreach (var item in query1)
{
Console.Write("{0}, ",item);
}
Console.WriteLine(); var query2 = from item in array //查询array中所以大于10小于40的元素
where item > 10 && item < 40
select item; foreach (var item in query2)
{
Console.Write("{0}, ", item);
}
Console.WriteLine(); var query3 = from item in array //查询array中小于10或者大于40的元素
where item < 10 || item > 40
select item; foreach (var item in query3)
{
Console.Write("{0}, ", item);
}

4.使用orderby子句进行排序

在一些场合,还需要对查询结果进行排序。在LINQ中,通过orderby子句对查询结果进行排序操作。

orderby子句格式为:orderby element [ascending|descending],其中element是要进行排序的字段,可以是数据源中的数据,也可以是对元素操作的结果。

[ascending|descending]是排序类型,ascending为升序,descending为降序,默认请客下为ascending。

示例代码:

               int[] array = { 1, 3, 9, 5, 16, 20, 54, 60, 18, 37 };
var query1 = from item in array //升序
orderby item
select item;
foreach (var item in query1)
{
Console.Write("{0}, ", item);
}
Console.WriteLine(); var query2 = from item in array //降序
orderby item descending
select item;
foreach (var item in query2)
{
Console.Write("{0}, ", item);
}
Console.WriteLine();

在LINQ中,orderby子句可以同时指定多规排序元素,还可以为每个元素指定独立的排序类型。orderby语句后的第一个排序元素为主要排序,第二个为次要排序,以此类推。

示例代码如下:

               Student[] students = {
new Student() {Name="乔峰",Age=20,XingBie="男" },
new Student() {Name="欧阳修",Age=22,XingBie="男" },
new Student() {Name="王五",Age=19,XingBie="男" },
new Student() {Name="王丹",Age=20,XingBie="女" },
new Student() {Name="倾国倾城",Age=18,XingBie="女" }
};
//主要按姓名长度从小到大,次要按年龄从大到小
var query3 = from stu in students
orderby stu.Name.Length ascending, stu.Age descending
select stu;
foreach (var item in query3)
{
Console.WriteLine(item);
}

5.使用group子句进行分组

在LINQ中,用group子句实现对查询结果的分组操作。group子句的常用格式为:group element by key。其中,element表示作为查询结果返回的元素,key表示分组条件。

group子句返回类型为IGrouping<TKey,TElement>的查询结果。

示例代码如下:

                Student[] students = {
new Student() {Name="乔峰",Age=22,XingBie="男" },
new Student() {Name="欧阳修",Age=22,XingBie="男" },
new Student() {Name="王五",Age=19,XingBie="男" },
new Student() {Name="王丹",Age=19,XingBie="女" },
new Student() {Name="倾国倾城",Age=19,XingBie="女" }
};
//按学生性别分组
var query1 = from stu in students
group stu by stu.XingBie;
foreach (var grp in query1)
{
Console.WriteLine(grp.Key);
foreach (var item in grp)
{
Console.WriteLine(item);
}
}
//按多条件分组,按性别和年龄分组
var query2 = from stu in students
group stu by new { stu.XingBie, stu.Age };
foreach (var grp in query2)
{
Console.WriteLine("{0}---{1}",grp.Key.XingBie,grp.Key.Age);
foreach (var item in grp)
{
Console.WriteLine(item);
}
}

有时候需要对分组的结果进行排序、再次查询等操作。这就需要使用into关键字将group查询的结果保存到一个临时变量,并且必须使用select子句对其进行重新查询。

into关键字语法为:group element by key into grp,其中,tmpGrp表示一个本地变量,用来临时保存group产生的结果,提供后面的LINQ子句使用。

示例代码如下:

             Student[] students = {
new Student() {Name="乔峰",Age=22,XingBie="男" },
new Student() {Name="欧阳修",Age=22,XingBie="男" },
new Student() {Name="王五",Age=19,XingBie="男" },
new Student() {Name="王丹",Age=19,XingBie="女" },
new Student() {Name="倾国倾城",Age=19,XingBie="女" }
}; var query3 = from stu in students
group stu by stu.Age into grp
orderby grp.Key descending
select grp;
foreach (var grp in query3)
{
Console.WriteLine("{0}岁的学生:", grp.Key);
foreach (var item in grp)
{
Console.WriteLine(item);
}
}

【C#】LINQ的更多相关文章

  1. 【转】Linq表达式、Lambda表达式你更喜欢哪个?

    [转]Linq表达式.Lambda表达式你更喜欢哪个? 什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相 ...

  2. 【2017-06-02】Linq高级查询,实现分页组合查询。

    1.以XXX开头 2.以XXX结尾 3.模糊查询 4.求个数 5.求最大值 6.求最小值 7.求平均值 8.求和 9.升序 10.降序 11.分页 Skip()跳过多少条 Take()取多少条 12. ...

  3. 【转】Linq Group by

    http://www.cnblogs.com/death029/archive/2011/07/23/2114877.html 1.简单形式: var q = from p in db.Product ...

  4. 【转】【收藏】LINQ学习心得分享--------(二)LINQ语法详解

    原地址:http://blog.csdn.net/xuemoyao/article/details/8053444   通过上一章节的学习,相信大家已经掌握了学习LINQ的前期的准备知识.在这一节里, ...

  5. 【转】 LINQ To SQL 语法及实例大全

    LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子 ...

  6. 【转】Linq实现DataTable行列转换

    出处:http://www.cnblogs.com/li-peng/ 转换前的table: 转换后的table: 代码里有详细的说明, 还有一些参数我都截图了下面有 using System;usin ...

  7. 【.NET】Linq几样特点

    LinQ 是 .net framework 3.5的技术,对集合的查询和操作十分方便,结合LinQ Provider ,可以更方便操作XML和SQL(或Entity). LinQ有6样常用的特性: 自 ...

  8. 【2017-06-01】Linq基础+Lambda表达式实现对数据库的增删改查

    一.Linq to sql 类 高集成化的数据库访问技术 使用Linq可以代替之前的Ado.Net.省去了自己敲代码的实体类和数据访问类的大量工作. 实体类: 添加一个Linq to sql 类 -- ...

  9. 【转发】Linq To EF添加记录后获取添加的自增ID和叫“ID”的列不是自增列不让插入的问题

    1:添加记录后,如何获取新添加的ID的值 比如,一个实体 TestEntity   对应一个表TestEntity(ID主键自增,Name,age),使用linq to ef   添加一条记录后,如何 ...

  10. 【转】LINQ多表关联关联条件

    转:http://www.dingcankong.com/linq%E4%B8%A4%E8%A1%A8%E8%81%94%E5%90%88%E6%9F%A5%E8%AF%A2/ 答案如下: var m ...

随机推荐

  1. HTMLTestRunner生成报告 中文展示乱码的问题

  2. ubuntu 14.04 no valid active connections found

    ubuntu 14.04 强制重启后出现不能上网,点击connection information 后出现error: no valid active connections found 解决办法是在 ...

  3. SSH开发中的注解使用

    在SSH中使用注解可以减少配置XML文件,毕竟随着项目规模的扩大,配置bean将把Spring的配置文件(applicationContext.xml)变得很混乱 在Spring的配置文件中开启注解扫 ...

  4. Python Twisted系列教程4:由Twisted支持的诗歌客户端

    作者:dave@http://krondo.com/twisted-poetry/  译者:杨晓伟(采用意译) 你可以在这里从头开始阅读这个系列. 第一个twisted支持的诗歌服务器 尽管Twist ...

  5. 【树莓派】开机自启动脚本方法之一(.Desktop文件)

    转载处: 又一个让树莓派开机运行Python脚本的方法 Linux 创建启动器(.Desktop文件) 首先,树莓派使用的是官方推荐的镜像:RASPBIAN: 在树莓派上常常会需要开机自启动pytho ...

  6. linux安装xgboost

    在学校服务器上安装xgboost,事先我已经安装了anaconda,但是因为师兄已经装了python所以没加入到path. 网上的方法一般都要编译,另外官方的下载方法要联网..总之出了一堆错,最终还是 ...

  7. ubuntu双网卡准备配置

    近日有个需求,交换机有两台,做了堆叠,服务器双网卡,每个分别连到一台交换机上.这样就需要将服务器的网卡做成主备模式,以增加安全性,使得当其中一个交换机不通的时候网卡能够自动切换. 整体配置不难,网上也 ...

  8. (转)CSS布局-负边距-margin

    css中的负边距(negative margin)是布局中的一个常用技巧,只要运用得合理常常会有意想不到的效果.很多特殊的css布局方法都依赖于负边距,所以掌握它的用法对于前端的同学来说,那是必须的. ...

  9. 在线HTTP POST/GET接口测试工具

    在线HTTP POST/GET接口测试工具 http://www.atool.org/httptest.php

  10. Java多线程-线程的交互

    一.线程交互的基础知识void notify():唤醒在此对象监视器上等待的单个线程. void notifyAll():唤醒在此对象监视器上等待的所有线程. void wait():导致当前的线程等 ...