LINQ 簡介
語言整合查詢 (LINQ) 是 Visual Studio 2008 和 .NET Framework 3.5 版中引入的創新功能。
傳統上,針對資料的查詢都是以簡單的字串表示,而沒有編譯時類型檢查或 IntelliSense 支援。此外,您還必須針對以下各種資料來源學習不同的查詢語言:SQL 資料庫、XML 文件、各種 Web 服務等等。 透過LINQ, 您可以使用語言關鍵字和熟悉的運算子針對強類型化物件集合編寫查詢。
在 Visual Studio 中,可以為下列資料來源撰寫 LINQ 查詢:SQL Server 資料庫、XML 文件、ADO.NET 資料集,以及支援 IEnumerable 或泛型 IEnumerable
使用需求:項目 ≥ .NET Framework 3.5 。
一、介紹 LINQ 查詢
查詢是一種從資料來源擷取資料的運算式。隨著時間的推移,人們已經為各種資料來源開發了不同的語言;例如,用於關聯式資料庫的 SQL 和用於 XML 的 XQuery。因此,開發人員必須針對他們必須支援的每種資料來源或資料格式而學習新的查詢語言。
LINQ 透過提供一種跨資料來源和資料格式使用資料的一致模型,簡化了這一情況。在 LINQ 查詢中,總是會用到物件。可以使用相同的編碼模式來查詢和轉換 XML 文件、SQL 資料庫、ADO.NET 資料集、.NET 集合中的資料以及對其有 LINQ 提供者可用的任何其他格式的資料。
1.1 查詢作業的三個部分
操作三部曲:①取資料來源 ②建立查詢 ③在執行查詢在 LINQ 中,查詢的執行與查詢本身截然不同;換句話說,查詢本身指的是只建立查詢變量,不檢索任何資料。
1.2 資料來源
可查詢類型不需要進行修改或特殊處理就可以用作 LINQ 資料來源。如果來源資料尚未以可查詢類型出現在記憶體中,則 LINQ 提供者必須以此方式表示來源資料。例如,LINQ to XML 將 XML 文件載入到可查詢的 XElement 類型中:
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); } } }
在 LINQ to SQL 中,首先需要建立物件關係對應。 針對這些物件編寫查詢,然後由 LINQ to SQL 在執行時間處理與資料庫的通訊。
0 2 4 6
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();
结果:
4
若要强制立即执行任意查询并缓存其结果,可以调用 ToList
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(); } }
以上就是C#开始使用 LINQ (上)的内容,更多相关内容请关注PHP中文网(www.php.cn)!