目錄
什么是查询句法(Query Syntax)?
查询句法的例子:
查询句法 - 理解from和select子句:
查询句法 - 理解where和orderby子句:
查询句法 - 用投影(Projection)来转换数据
查询句法 - 理解延迟执行(Deferred Execution)和使用ToList() 和ToArray()
结语
首頁 資料庫 mysql教程 新Orcas语言特性-查询句法

新Orcas语言特性-查询句法

Jun 07, 2016 pm 06:05 PM

新Orcas语言特性-查询句法

【原文地址】
【原文发表日期】 Saturday, April 21, 2007 2:12

上个月我开始了一个贴子系列,讨论作为Visual Studio和.NET框架Orcas版本一部分发布的一些新的VB和C#语言特性。下面是该系列的前三篇贴子的链接:

今天的贴子要讨论另一个基础性的新语言特性:查询句法(Query Syntax)

什么是查询句法(Query Syntax)?

查询句法是使用标准的LINQ查询运算符来表达查询时一个方便的声明式简化写法。该句法能在代码里表达查询时增进可读性和简洁性,读起来容易,也容易让人写对。Visual Studio 对查询句法提供了完整的intellisense和编译时检查支持。

在底下,C#和VB编译器则把查询句法的表达式翻译成明确的方法调用代码,这样的代码利用了Orcas中的新的和语言特性。

查询句法的例子:

在我以前的语言系列贴子里,我示范了你可以象下面这样声明一个Person类:

然后我们可以使用下面这样的代码,用一些个人信息来生成一个List集合实例,然后使用查询句法来对该集合做一个LINQ查询,只取出那些姓(last name)的首字母为G的人,按名字(first name)来排序(升序):

上面查询句法的表达式在语意上与下面明确使用LINQ和的代码是等同的:

使用查询句法方法的好处是,结果会是稍微容易读写些,这在表达式变得更繁复时尤其如此。

查询句法 - 理解from和select子句:

在C#中,每个查询表达式的句法从from子句开始,以select或group子句结束。from子句表示你要查询什么数据。select子句则表示你要返回什么数据,且应该以什么构形返回。

譬如,让我们再来看一下我们对List集合的查询:

在上面的代码片段里,"from p in people"表示了我要对"people" 这个集合做一个LINQ查询,我将用参数"p"代表我正查询的输入序列的每个项。我们将参数命名为"p" 这个事实是无关紧要的,我完全可以很容易地将其命名为"o", "x", "person"或我想要的任何名字。

在上面的代码片段里,语句结尾的"select p"子句表示,作为查询的结果,我要返回一个Person对象的IEnumerable序列。这是因为"people"集合包含了Person类型的对象,而参数p则代表了输入序列中的Person对象。因此,该查询句法表达式的结果数据类型是IEnumerable

假如不是返回Person对象,我想返回该集合中的人的名字,我可以把查询改写成这样:

注意上面我不再说"select p",而是说"select p.FirstName"。这表示我不想返回一串Person对象,而是想返回一串字符串,由Person对象的FirstName属性(该属性是个字符串)填充而来。 因此,该查询句法表达式的结果类型是 IEnumerable

针对数据库的查询句法的例子

LINQ的妙处在于,我可以针对任何数据类型使用完全一样的查询句法。譬如,我可以使用Orcas提供的新LINQ到SQL对象关系映射器支持,对SQL服务器的Northwind数据库进行建模,生成下面这些类(请来学习该如何实现):

在上面定义好类模型之后(以及它与数据库间的映射关系),然后我就可以写个查询句法的表达式取出那些单价大于99元的产品:

在上面的代码片段里,我表示我要对NorthwindDataContext类的Products表进行一个LINQ查询,NorthwindDataContext类是由Visual Studio orcas的ORM设计器生成的。"select p"表示我要返回匹配我的查询的一串Product对象,因此,该查询句法表达式的结果数据类型是IEnumerable

就象前面List查询句法的例子一样,C# 编译器会把我们的声明式查询句法翻译成明确的扩展方法调用(使用Lambda表达式作为参数)。在上面的LINQ到SQL的例子的情形下,这些Lambda表达式会被转化成SQL命令,然后在SQL服务器上做运算(这样,只有那些匹配查询条件的Product记录行会返回到我们的应用中)。促成这个Lambda->SQL 转化的机制的细节可见于我的的"Lambda表达式树"部分。

查询句法 - 理解where和orderby子句:

在一个查询句法表达式开头的"from" 子句和结尾的"select"子句之间,你可以使用最常见的LINQ查询运算符来过滤和转换你在查询的数据。两个最常用的子句是"where"和"orderby"。这两个子句处理对结果集的过滤和排序。

譬如,要从Northwind数据库里返回按字母降序排列的分类名称列表,过滤条件是只包括那些含有5个以上产品的分类,我们可以编写下面这样的查询句法来用LINQ到SQL对我们的数据库做查询:

在上面的表达式里,我们加了 "where c.Products.Count > 5" 子句来表示我们只要那些含有5个以上产品的分类。这利用了数据库中产品和分类间的LINQ到SQL的ORM映射的关联。在上面的表达式中,我也加了"order by c.CategoryName descending"子句来表示我要将结果集按名称降序排列。

LINQ到SQL然后就会在使用这个表达式查询数据库时,生成下列SQL:

Select [t0].[CategoryName] FROM [dbo].[Categories] AS [t0]
Where ((
Select COUNT(*)
FROM [dbo].[Products] AS [t1]
Where [t1].[CategoryID] = [t0].[CategoryID]
)) > 5
ORDER BY [t0].[CategoryName] DESC

注意,LINQ到SQL很聪明,只返回了我们所需的单个字段(分类名称), 而且它是在数据库层做了所有的过滤和排序,使得该查询效率非常高。

查询句法 - 用投影(Projection)来转换数据

先前我指出的一个要点是,"select" 子句表示了你要返回的数据,以及这个数据的构形是什么

譬如,假如你有个象下面这样的"select p" 子句,这里p的类型是Person,然后,它就会返回一串Person对象:

LINQ和查询句法提供的一个非常强大的功能是允许你定义跟被查询的数据分开的新的类型,然后用新的类型来控制查询返回的数据的形状和结构。

譬如,假设我们定义了一个新的AlternatePerson类,内含一个FullName属性,而不是我们原先的Person类内的分开的FirstName和LastName属性:

然后我就可以使用下面的LINQ查询句法来查询我原先的List集合,用下面的查询句法将结果转换成一串AlternatePerson对象:

注意看,我们是如何在上面的表达式里的"select"子句里,使用里讨论过的新的来创建新的AlternatePerson实例,同时设置它的属性的。也注意我是如何连接我们原先Person类的FirstName和LastName属性,然后将其赋值给FullName属性的。

对数据库使用查询句法投影

这个投影特性在操作从象数据库这样一个远程数据提供器那里取回的数据时,会变得难以置信地有用,因为它提供给我们一个优雅的方式,来表示我们的ORM应该从数据库实际取回哪些数据字段。

譬如,假设我用了LINQ到SQL的ORM提供器对Northwind数据库建模,生成下面这些类:

通过编写下面这个LINQ查询,我告诉LINQ到SQL我要返回一串Product对象:

填充Product类所需的所有字段都将作为上面查询的一部分从数据库中返回,由LINQ到SQL orM执行的raw SQL看上去象下面这样:

Select [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID],
[t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock],
[t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
FROM [dbo].[Products] AS [t0]
Where [t0].[UnitPrice] > 99

在一些场景下,我不需要也不用所有这些字段,我可以定义一个下面这样的新的MyProduct类,只拥有Product类具有的部分属性,以及一个Product类并不具有的额外属性,TotalRevenue (注: 对那些不熟悉C#的,Decimal?句法表示我们的UnitPrice属性是个nullable值):

然后我就可以使用下面这个查询,使用查询句法的投影功能来构造我要从数据库返回的数据的形状:

这表明,不是返回一串Product对象,我要MyProduct对象,我只要其中三个属性被赋值,LINQ到SQL就会很聪明地调整要执行的raw SQL语句,从数据库只返回那三个需要的产品字段:

Select [t0].[ProductID], [t0].[ProductName], [t0].[UnitPrice]
FROM [dbo].[Products] AS [t0]
Where [t0].[UnitPrice] > 99

为炫耀起见,我也可以填充MyProduct类的第四个属性,即TotalRevenue属性。我要这个值等于我们产品目前的销售额的总量。这个值在Northwind数据库中并没有作为一个预先算好的字段而存在。而是,你需要在Products表和Order Details表间做一个关联,然后计算出一个给定产品对应的所有的Order Detail 行的总量。

非常酷的是,我可以在Product类的OrderDetails关联上使用LINQ的 Sum 这个,编写一个作为我的查询句法投影一部分的乘法,来计算这个值:

LINQ到SQL就会非常聪明地使用下面这个SQL在SQL数据库里做运算:

Select [t0].[ProductID], [t0].[ProductName], [t0].[UnitPrice], (
Select SUM([t2].[value])
FROM (
Select [t1].[UnitPrice] * (CONVERT(Decimal(29,4),[t1].[Quantity])) AS [value], [t1].[ProductID]
FROM [dbo].[Order Details] AS [t1]
) AS [t2]
Where [t2].[ProductID] = [t0].[ProductID]
) AS [value]
FROM [dbo].[Products] AS [t0]
Where [t0].[UnitPrice] > 99

查询句法 - 理解延迟执行(Deferred Execution)和使用ToList() 和ToArray()

在默认情形下,查询句法表达式的结果的类型是IEnumerable。在上面的例子里,你会注意到所有的查询句法赋值是给IEnumerable, IEnumerable, IEnumerable, IEnumerable, 和 IEnumerable 变量的。

IEnumerable接口的一个很好的特征是,实现它们的对象可以把实际的查询运算延迟到开发人员第一次试图对返回值进行迭代(这是通过使用最早在VS 2005中C# 2.0 中引进的yield构造来达成的)时才进行。LINQ和查询句法表达式利用了这个特性,将查询的实际运算延迟到了你第一次对返回值进行循环时才进行。假如你对IEnumerable的结果从不进行迭代的话,那么查询根本就不会执行。

譬如,考虑下面这个LINQ到SQL的例子:

不是在查询句法表达式声明的时候,而是在我们第一次试图对结果进行循环(上面红箭头标志的地方),才会去访问数据库以及取出填充Category对象所需的值。

这个延迟运算的行为结果变得非常有用,因为它促成了一些把多个LINQ查询和表达式链在一起的强有力的组合场景。譬如,我们可以把一个表达式的结果喂给另一个表达式,然后通过延迟运算,允许象LINQ 到SQL这样的ORM根据整个表达式树来优化raw SQL。我将在以后的一个博客贴子里对这样的场景做示范说明。

如何立刻对查询句法表达式做运算

如果你不要延迟查询运算,而是要对它们立刻就执行运算,你可以使用内置的ToList() 和ToArray() 运算符来返回一个包括了结果集的List或者数组。

譬如,要返回一个基于范型的 List 集合的话:

要返回一个数组的话:

在上面两种情形下,会立刻访问数据库,填充Category对象。

结语

查询句法在使用标准的LINQ查询运算符来表达查询时,提供了非常方便的声明式简化写法。它提供的句法可读性非常高,可以针对任何类型的数据(内存中的集合,数组,XML内容,以及象数据库这样的远程数据提供器,web服务等等)进行查询。一旦你熟悉这个句法后,你可以在任何地方应用这个知识。

在不远的将来,我将结束本语言系列的最后一部分,该部分将讨论新的匿名类型特性。然后我将转而讨论在实际应用中使用所有这些语言特性的一些非常实用的例子(特别是针对数据库和XML文件使用LINQ的例子)。

希望本文对你有所帮助,

Scott

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1422
52
Laravel 教程
1316
25
PHP教程
1267
29
C# 教程
1239
24
與MySQL中使用索引相比,全表掃描何時可以更快? 與MySQL中使用索引相比,全表掃描何時可以更快? Apr 09, 2025 am 12:05 AM

全表掃描在MySQL中可能比使用索引更快,具體情況包括:1)數據量較小時;2)查詢返回大量數據時;3)索引列不具備高選擇性時;4)複雜查詢時。通過分析查詢計劃、優化索引、避免過度索引和定期維護表,可以在實際應用中做出最優選擇。

mysql:簡單的概念,用於輕鬆學習 mysql:簡單的概念,用於輕鬆學習 Apr 10, 2025 am 09:29 AM

MySQL是一個開源的關係型數據庫管理系統。 1)創建數據庫和表:使用CREATEDATABASE和CREATETABLE命令。 2)基本操作:INSERT、UPDATE、DELETE和SELECT。 3)高級操作:JOIN、子查詢和事務處理。 4)調試技巧:檢查語法、數據類型和權限。 5)優化建議:使用索引、避免SELECT*和使用事務。

MySQL:初學者的數據管理易用性 MySQL:初學者的數據管理易用性 Apr 09, 2025 am 12:07 AM

MySQL適合初學者使用,因為它安裝簡單、功能強大且易於管理數據。 1.安裝和配置簡單,適用於多種操作系統。 2.支持基本操作如創建數據庫和表、插入、查詢、更新和刪除數據。 3.提供高級功能如JOIN操作和子查詢。 4.可以通過索引、查詢優化和分錶分區來提升性能。 5.支持備份、恢復和安全措施,確保數據的安全和一致性。

MySQL的角色:Web應用程序中的數據庫 MySQL的角色:Web應用程序中的數據庫 Apr 17, 2025 am 12:23 AM

MySQL在Web應用中的主要作用是存儲和管理數據。 1.MySQL高效處理用戶信息、產品目錄和交易記錄等數據。 2.通過SQL查詢,開發者能從數據庫提取信息生成動態內容。 3.MySQL基於客戶端-服務器模型工作,確保查詢速度可接受。

MySQL:世界上最受歡迎的數據庫的簡介 MySQL:世界上最受歡迎的數據庫的簡介 Apr 12, 2025 am 12:18 AM

MySQL是一種開源的關係型數據庫管理系統,主要用於快速、可靠地存儲和檢索數據。其工作原理包括客戶端請求、查詢解析、執行查詢和返回結果。使用示例包括創建表、插入和查詢數據,以及高級功能如JOIN操作。常見錯誤涉及SQL語法、數據類型和權限問題,優化建議包括使用索引、優化查詢和分錶分區。

說明InnoDB重做日誌和撤消日誌的作用。 說明InnoDB重做日誌和撤消日誌的作用。 Apr 15, 2025 am 12:16 AM

InnoDB使用redologs和undologs確保數據一致性和可靠性。 1.redologs記錄數據頁修改,確保崩潰恢復和事務持久性。 2.undologs記錄數據原始值,支持事務回滾和MVCC。

MySQL的位置:數據庫和編程 MySQL的位置:數據庫和編程 Apr 13, 2025 am 12:18 AM

MySQL在數據庫和編程中的地位非常重要,它是一個開源的關係型數據庫管理系統,廣泛應用於各種應用場景。 1)MySQL提供高效的數據存儲、組織和檢索功能,支持Web、移動和企業級系統。 2)它使用客戶端-服務器架構,支持多種存儲引擎和索引優化。 3)基本用法包括創建表和插入數據,高級用法涉及多表JOIN和復雜查詢。 4)常見問題如SQL語法錯誤和性能問題可以通過EXPLAIN命令和慢查詢日誌調試。 5)性能優化方法包括合理使用索引、優化查詢和使用緩存,最佳實踐包括使用事務和PreparedStatemen

為什麼要使用mysql?利益和優勢 為什麼要使用mysql?利益和優勢 Apr 12, 2025 am 12:17 AM

選擇MySQL的原因是其性能、可靠性、易用性和社區支持。 1.MySQL提供高效的數據存儲和檢索功能,支持多種數據類型和高級查詢操作。 2.採用客戶端-服務器架構和多種存儲引擎,支持事務和查詢優化。 3.易於使用,支持多種操作系統和編程語言。 4.擁有強大的社區支持,提供豐富的資源和解決方案。

See all articles