C#开始使用 LINQ

C#开始使用 LINQ
LINQ 简介

语言集成查询 (LINQ) 是 Visual Studio 2008 和 .NET Framework 3.5 版中引入的一项创新功能。

传统上,针对数据的查询都是以简单的字符串表示,而没有编译时类型检查或 IntelliSense 支持。此外,您还必须针对以下各种数据源学习一种不同的查询语言:SQL 数据库、XML 文档、各种 Web 服务等等。 通过LINQ, 您可以使用语言关键字和熟悉的运算符针对强类型化对象集合编写查询。

C#开始使用 LINQ (上)

在 Visual Studio 中,可以为以下数据源编写 LINQ 查询:SQL Server 数据库、XML 文档、ADO.NET 数据集,以及支持 IEnumerable 或泛型 IEnumerable<T> 接口的任意对象集合。

使用要求:项目 ≥ .NET Framework 3.5 。

一、介绍 LINQ 查询

查询是一种从数据源检索数据的表达式。随着时间的推移,人们已经为各种数据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。因此,开发人员不得不针对他们必须支持的每种数据源或数据格式而学习新的查询语言。

LINQ 通过提供一种跨数据源和数据格式使用数据的一致模型,简化了这一情况。在 LINQ 查询中,始终会用到对象。可以使用相同的编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、.NET 集合中的数据以及对其有 LINQ 提供程序可用的任何其他格式的数据。

1.1 查询操作的三个部分

操作三部曲:①取数据源 ②创建查询 ③执行查询

internal class Program

{

private static void Main(string[] args)

{

//1.获取数据源

var nums = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

//2.创建查询

var numQuery =

from num in nums

where (num % 2) == 0

select num;

//3.执行查询

foreach (var num in numQuery)

{

Console.WriteLine("{0}", num);

}

}

}

C#开始使用 LINQ (上)

下图显示了完整的查询操作。在 LINQ 中,查询的执行与查询本身截然不同;换句话说,查询本身指的是只创建查询变量,不检索任何数据。

C#开始使用 LINQ (上)

1.2 数据源

在上一个示例中,由于数据源是数组,因此它隐式支持泛型 IEnumerable<T> 接口。支持 IEnumerable<T> 或派生接口(如泛型 IQueryable<T>)的类型称为可查询类型。

可查询类型不需要进行修改或特殊处理就可以用作 LINQ 数据源。如果源数据还没有作为可查询类型出现在内存中,则 LINQ 提供程序必须以此方式表示源数据。例如,LINQ to XML 将 XML 文档加载到可查询的 XElement 类型中:

//从 XML 中创建数据源

//using System.Xml.Linq;

var contacts = XElement.Load(@"c:\xxx.xml");

在 LINQ to SQL 中,首先需要创建对象关系映射。 针对这些对象编写查询,然后由 LINQ to SQL 在运行时处理与数据库的通信。

var db = new Northwnd(@"c:\northwnd.mdf");

//查询在伦敦的客户

var custQuery= from cust in db.Customers

where cust.City == "London"

select cust;

Customers 表示数据库中的特定表

1.3 查询

查询指定要从数据源中检索的信息。 查询还可以指定在返回这些信息之前如何对其进行排序、分组和结构化。 查询存储在查询变量中,并用查询表达式进行初始化。

之前的示例中的查询是从整数数组中返回所有的偶数。 该查询表达式包含三个子句:from、where 和 select。(如果您熟悉 SQL,您会注意到这些子句的顺序与 SQL 中的顺序相反。)from 子句指定数据源,where 子句指定应用筛选器,select 子句指定返回的元素的类型。 目前需要注意的是,在 LINQ 中,查询变量本身不执行任何操作并且不返回任何数据。 它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。

1.4 查询执行

1.延迟执行

如前所述,查询变量本身只是存储查询命令。 实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。 此概念称为“延迟执行”。

2.强制立即执行

对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。Count、Max、Average 和 First 就属于此类查询。由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。

var numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

var evenNumQuery =

from num in numbers

where (num % 2) == 0

select num;

var evenNumCount = evenNumQuery.Count();

C#开始使用 LINQ (上)

若要强制立即执行任意查询并缓存其结果,可以调用 ToList<TSource> 或 ToArray<TSource> 方法。

var numQuery2 =(from num in numbers

where (num % 2) == 0

select num).ToList();

var numQuery3 =(from num in numbers

where (num % 2) == 0

select num).ToArray();

此外,还可以通过在紧跟查询表达式之后的位置放置一个 foreach 循环来强制执行查询。但是,通过调用 ToList 或 ToArray,也可以将所有数据缓存在单个集合对象中。

二、基本 LINQ 查询操作

2.1 获取数据源:from

在 LINQ 查询中,第一步是指定数据源。像在大多数编程语言中一样,必须先声明变量,才能使用它。在 LINQ 查询中,最先使用 from 子句的目的是引入数据源和范围变量。

//queryAllCustomers 是 IEnumerable<Cutsomer> 类型

//数据源 (customers) 和范围变量 (cust)

var queryAllCustomers = from cust in customers

select cust;

范围变量类似于 foreach 循环中的迭代变量,但在查询表达式中,实际上不发生迭代。执行查询时,范围变量将用作对 customers 中的每个后续元素的引用。因为编译器可以推断 cust 的类型,所以您不必显式指定此类型。

2.2 筛选:where

也许最常用的查询操作是应用布尔表达式形式的筛选器。此筛选器使查询只返回那些表达式结果为 true 的元素。使用 where 子句生成结果。实际上,筛选器指定从源序列中排除哪些元素。

var queryLondonCustomers = from cust in customers

       where cust.City = "London"

      select cust;

您可以使用熟悉的 C# 逻辑 AND(&&)和 OR(||) 运算符来根据需要在 where 子句中应用任意数量的筛选表达式。

where cust.City = "London" && cust.Name = "Devon"

where cust.City = "London" || cust.Name = "Paris"

2.3 排序:orderby

通常可以很方便地将返回的数据进行排序。orderby 子句将使返回的序列中的元素按照被排序的类型的默认比较器进行排序。

var queryLondonCustomers = from cust in customers

where cust.City = "London"

orderby cust.Name descending

select cust;

因为 Name 是一个字符串,所以默认比较器执行从 A 到 Z 的字母排序。若要按相反顺序(从 Z 到 A)对结果进行排序,请使用 orderby…descending 子句。

2.4 分组:group

  使用 group 子句,您可以按指定的键分组结果。

var queryLondonCustomers = from cust in customers

group cust by cust.City;

foreach (var queryLondonCustomer in queryLondonCustomers)

{

Console.WriteLine(queryLondonCustomer.Key);

foreach (var cust in queryLondonCustomer)

{

Console.WriteLine(cust.Name);

}

}

您可以指定结果应按 City 分组,以便位于伦敦或巴黎的所有客户位于各自组中。

在本例中,cust.City 是键。

在使用 group 子句结束查询时,结果采用列表的列表形式。列表中的每个元素是一个具有 Key 成员及根据该键分组的元素列表的对象。在循环访问生成组序列的查询时,您必须使用嵌套的 foreach 循环。外部循环用于循环访问每个组,内部循环用于循环访问每个组的成员。

如果您必须引用组操作的结果,可以使用 into 关键字来创建可进一步查询的标识符。

//custQuery 是 IEnumable<IGrouping<string, Customer>> 类型

var custQuery = from cust in customers

group cust by cust.City

into custGroup

where custGroup.Count() > 2

orderby custGroup.Key

select custGroup;

这里的查询只返回那些包含两个以上的客户的组。

2.5 联接:join

联接运算创建数据源中没有显式建模的序列之间的关联。例如,您可以执行联接来查找位于同一地点的所有客户和经销商。在 LINQ 中,join 子句始终针对对象集合而非直接针对数据库表运行。

var innerJoinQuery = from cust in customers

  join dist in distributors on cust.City equals dist.City

  select new {CustomerName = cust.Name, DistributorName = dist.Name};

在 LINQ 中,join 子句始终针对对象集合而非直接针对数据库表运行。

在 LINQ 中,您不必像在 SQL 中那样频繁使用 join,因为 LINQ 中的外键在对象模型中表示为包含项集合的属性。

from order in Customer.Orders...

2.6 选择(投影):select

  select 子句生成查询结果并指定每个返回的元素的“形状”或类型。

  例如,您可以指定结果包含的是整个 Customer 对象、仅一个成员、成员的子集,还是某个基于计算或新对象创建的完全不同的结果类型。当 select 子句生成除源元素副本以外的内容时,该操作称为“投影”。

三、使用 LINQ 进行数据转换

  语言集成查询 (LINQ) 不仅可用于检索数据,而且还是一个功能强大的数据转换工具。通过使用 LINQ 查询,您可以将源序列用作输入,并采用多种方式修改它以创建新的输出序列。您可以通过排序和分组来修改该序列,而不必修改元素本身。但是,LINQ 查询的最强大的功能是能够创建新类型。这一功能在 select 子句中实现。 例如,可以执行下列任务:

3.1 将多个输入联接到一个输出序列

class Student

{

public string Name { get; set; }

public int Age { get; set; }

public string City { get; set; }

public List<int> Scores { get; set; }

}

class Teacher

{

public int Id { get; set; }

public string Name { get; set; }

public int Age { get; set; }

public string City { get; set; }

}

学生和老师两个类

internal class Program

{

private static void Main(string[] args)

{

//创建第一个数据源

var students = new List<Student>()

{

new Student()

{

Age = 23,

City = "广州",

Name = "小C",

Scores = new List<int>(){85,88,83,97}

},

new Student()

{

Age = 18,

City = "广西",

Name = "小明",

Scores = new List<int>(){86,78,85,90}

},

new Student()

{

Age = 33,

City = "梦里",

Name = "小叁",

Scores = new List<int>(){86,68,73,97}

}

};

//创建第二个数据源

var teachers = new List<Teacher>()

{

new Teacher()

{

Age = 35,

City = "梦里",

Name = "啵哆"

},

new Teacher()

{

Age = 28,

City = "云南",

Name = "小红"

},

new Teacher()

{

Age = 38,

City = "河南",

Name = "丽丽"

}

};

//创建查询

var peopleInDreams = (from student in students

where student.City == "梦里"

select student.Name)

.Concat(from teacher in teachers

where teacher.City == "梦里"

select teacher.Name);

//执行查询

foreach (var person in peopleInDreams)

{

Console.WriteLine(person);

}

Console.Read();

}

}

稿源:勤快学QKXue.Net
扩展阅读:
C#开始使用 LINQ (上)
http://qkxue.net/info/21835/nbsp-LINQ
C#开始使用 LINQ (下)
http://qkxue.net/info/21834/nbsp-LINQ

时间: 2024-11-15 00:59:48

C#开始使用 LINQ的相关文章

.NET深入解析LINQ框架(五:IQueryable、IQueryProvider接口详解)

阅读目录: 1.环路执行对象模型.碎片化执行模型(假递归式调用) 2.N层对象执行模型(纵横向对比链式扩展方法) 3.LINQ查询表达式和链式查询方法其实都是空壳子 4.详细的对象结构图(对象的执行原理) 5.IQueryable<T>与IQueryProvider一对一的关系能否改成一对多的关系 6.完整的自定义查询 1]. 环路执行对象模型.碎片化执行模型(假递归式调用) 这个主题扯的可能有点远,但是它关系着整个LINQ框架的设计结构,至少在我还没有搞懂LINQ的本意之前,在我脑海里一直频

.NET深入解析LINQ框架(一:LINQ优雅的前奏)

阅读目录: 1.LINQ简述 2.LINQ优雅前奏的音符 2.1.隐式类型 (由编辑器自动根据表达式推断出对象的最终类型) 2.2.对象初始化器 (简化了对象的创建及初始化的过程) 2.3.Lambda表达式 (对匿名方法的改进,加入了委托签名的类型推断并很好的与表达式树的结合) 2.4.扩展方法 (允许在不修改类型的内部代码的情况下为类型添加独立的行为) 2.5.匿名类型 (由对象初始化器推断得出的类型,该类型在编译后自动创建) 2.6.表达式目录树(用数据结构表示程序逻辑代码) 3.LINQ

.NET深入解析LINQ框架(二:LINQ优雅的前奏)

阅读目录: 1.LINQ框架的主要设计模型 1.1.链式设计模式 (以流水线般的链接方式设计系统逻辑) 1.2.链式查询方法(逐步加工查询表达式中的每一个工作点) 2.LINQ框架的核心设计原理 2.1.托管语言之上的语言(LINQ查询表达式) 2.2.托管语言构造的基础(LINQ依附通用接口与查询操作符对应的方法对接) 2.3.深入IEnumerable.IEnumerable<T>.Enumerable(LINQ to Object框架的入口) 2.4.深入IQueryable.IQuer

.NET深入解析LINQ框架(四:IQueryable、IQueryProvider接口详解)

阅读目录: 1.开篇介绍 2.扩展Linq to Object (应用框架具有查询功能) 2.1.通过添加IEnumerable<T>对象的扩展方法 2.2.通过继承IEnumerable<T>接口 2.3.详细的对象结构图 3.实现IQueryable<T> .IQueryProvider接口 3.1.延迟加载IEnumertor<T>对象(提高系统性能) 3.2.扩展方法的扩展对象之奥秘(this IQueryable<TSource> so

.NET深入解析LINQ框架(三:LINQ优雅的前奏)

阅读目录: 1.动态LINQ查询(动态构建Expression<T>表达式树) 2.DLR动态语言运行时(基于CLR之上的动态语言运行时) 1].动态LINQ查询(动态构建Expression<T>表达式树) 什么是动态LINQ查询?LINQ的编写是静态的,因为C#是基于静态类型系统原理设计的,在编写时已经确定类型,也就是在编译时就已经知道将要执行什么样的查询,条件是什么.排序方式是什么等等.那么很大一部分应用场合中我们需要根据用户的选择来查询数据源,以往我们都是通过判断的方式来拼

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

阅读目录: 1.LINQ执行表达式 在看本篇文章之前我假设您已经具备我之前分析的一些原理知识,因为这章所要讲的内容是建立在之前的一系列知识点之上的,为了保证您的阅读顺利建议您先阅读本人的LINQ系列文章的前几篇或者您已经具备比较深入的LINQ原理知识体系,防止耽误您的宝贵时间. 到目前为止我们对LINQ的执行原理已经很清楚了,从它的前期构想到它真正为我们所用都有足够的证据,但是似乎问题并没有我们想的那么简单,问题总是在我们使用中频频出现尤其是新技术的使用,当然有问题才能有进步. 一:LINQ执行

应用开发之Linq和EF

上一章笔者对于WinForm开发过程用到的几个知识点做了讲解.笔者们可以以此为开端进行学习.而本章我们来讲一个跟ORM思想有关的知识点.在讲之前让我们想一下关于JAVA的hibernate知识点.hibernate也是ORM框架.记得hibernate里面有一个叫HQL.先不管HQL的好与坏.主要是明白HQL的目地是什么.ORM的思想就是为了让用户在操作数据的时候用上面向对象的思想来看,而不是二维数据了.所以HQL笔者认为就是一个面向对象思想的SQL语句.那么为什么笔者要讲到HQL呢?事实上笔者

Linq to List

var lstMater = lst.GroupBy(w => new { w.materialId, w.name, w.isPass, w.description }). Select(g => new View_El_MyCourse_MaterialInfo { description = g.Key.description, isPass = g.Key.isPass, materialId = g.Key.materialId, name = g.Key.name }).Order

几种查询方法(lambda Linq Enumerable静态类方式)

1.需要一个数据源类: using System; using System.Collections.Generic; namespace Linq { public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } public class Data { public static List<Student> studentLi

Linq To Nhibernate 性能优化(入门级)

最近都是在用Nhibernate和数据库打交道,说实话的,我觉得Nhibernate比Ado.Net更好用,但是在对于一些复杂的查询Nhibernate还是比不上Ado.Net.废话不多说了,下面讲讲Linq To Nhibernate的性能优化. 第一点:应该要分清楚当前代码是在数据库上执行,还是在内存中执行(或者什么时候应该在数据库上做,什么时候应该在内存做) 我们在在做查询的时候,常见的使用方法 上面是使用了Iqueryable接口的,它会把数据先筛完了之后,再返回给我们 这个在数据库里呢