再试译ScottGu's Posts 之 VS2008之语言特性--查询语法--New Orcas Language Feature: Query Syntax...
學習一門新的語言,總要從其語法學起。為了方便大家學習,同時也為了自己學習,就將ScottGu的這篇關于3.5中增加的新的特性帖子譯了出來。這次我翻譯采用中漢對照的方式,不然像上次譯的那個那樣的話不但我自己譯起來不方便,大家讀起來也覺得不爽。
照原來,先將原貼地址貼出:http://weblogs.asp.net/scottgu/archive/2007/04/21/new-orcas-language-feature-query-syntax.aspx
Now Let's Begin:
Last month I started a series of posts covering some of the new VB and C# language features that are coming as part of the Visual Studio and .NET Framework "Orcas" release.? Here are pointers to the first three posts in my series:
上個月我開始了一系列關于作為VS和.NET Framework "Oracs" release版一部分的VB和C#語言的新特性的帖子。下面是該系列的前三個帖子的鏈接:
- Automatic Properties, Object Initializer and Collection Initializers
- Extension Methods
- Lambda Expressions
Today's blog post covers another fundamental new language feature: Query Syntax.
今天的帖子涵蓋了新語言特性的基礎:查詢語法
What is Query Syntax ?
什么是查詢語法?
Query syntax is a convenient declarative shorthand for expressing queries using the standard LINQ query operators.? It offers a syntax that increases the readability and clarity of expressing queries in code, and can be easy to read and write correctly.? Visual Studio provides complete intellisense and compile-time checking support for query syntax.
查詢語法是用標準的LINQ查詢操作符來聲來為表達式聲明的一個方便的速記方法。它提供了一種增強了程序的可讀性和明了性的語法,并且易讀易寫,寫的過程中不容易出現錯誤。VS為查詢語法提供了完全的智能提示和編譯時檢查。
Under the covers the C# and VB compilers take query syntax expressions and?translate them into?explicit method invocation code that utilizes the new Extension Method and Lambda Expression language features in "Orcas".
根據報道,C#和VB編譯器識別查詢語法表達式并將它們譯為強制聲明的方法,這些新方法利用了在"Orcas"中的新的"Extension Method"和Lambda Expression。
Query Syntax Example:
查詢語法事例:
In my previous language series posts, I demonstrated how you could declare a "Person" class like below:
在我本系統的前幾篇帖子中,我說明了如何聲明一個像下邊的類:
?
We?could then use the below code to instantiate a List<Person> collection with people values, and then use query syntax to perform a LINQ query over the collection and fetch only those people whose last name starts with the letter "G", sorted by the people's firstname (in ascending order):
我們可以利用下面的代碼來實例化一個具有peopeo的values的List<Person>,然后利用查詢語法在該collection中用LINQ查詢查詢出那些姓是以“G”字母開頭的人,并按名排序(倒序):
The query syntax expression above is semantically equivalent to the below code that uses LINQ extension methods and lambda expressions explicitly:
上邊的查詢語法在語義上和下面顯示調用LINQ extension methods和lambda expressions的代碼是等同的:
The benefit with using the query syntax approach?is that it ends up being a little easier to read and write.? This is especially true as the expression gets richer and more descriptive.
用查詢語法的好處是它更易讀和易寫一些,顯然是這樣,因為表達式變得更具有表達性。
Query Syntax - Understanding the From and Select Clauses:
查詢語法:了解From和Select的結構:
Every syntactic query expression in C# begins with a "from" clause and ends with either a "select" or "group" clause.? The "from" clause indicates what data you want to query.? The "select" clause indicates what data you want returned, and what shape it should be in.
在C#中,每一個查詢表達式的語法是以"from"開始,以“select”或“group"結束。"from"關鍵字表明了你想查詢哪些數據,"select"關鍵字表明了你想返回哪些數據,這些數據以什么類型返回。
For example, let's?look again at our query against the List<Person> collection:
例如,讓我們看一下對于List<Person>集合的查詢:
In the above code snippet the "from p in people" clause is indicating that I want to perform a LINQ query against the "people" collection, and that?I will use the parameter "p" to represent each item in the input sequence I am querying.? The fact that we named the parameter "p" is irrelevant - I could just have easily named it "o", "x", "person" or any other name I wanted.
在上邊的代碼片斷中,"from p in peple"聲明了我想從people集合中查詢出數據,并且聲明了將以參數"p"來代碼我查詢的每一個數據項。事實上我們將該參數命名為"p"跟查詢是無任何關聯的,我可以將它命名為"o","x","person"或其他任何我想命名的名字都可以。
In the above code snippet the "select p" clause at the end of the statement is indicating that I want to return an IEnumerable sequence of Person objects as the result of the query.? This is because the?"people" collection contains?objects of type "Person", and the p parameter represents?Person objects within the input sequence.? The datatype result of this query syntax expression is consequently of type IEnumerable<Person>.?
在上邊的代碼片斷中,表達式末尾的“select p"語句聲明了我想返回一個IEnumerable Person對象來作為我查詢的結果。這是因為"people"集合包括了"Person"類型的對象,并且參數"p"代表了Person對象。因此,該查詢表達式的返回的數據結果的類型是IEnumberable<Person>。
If instead of returning Person objects, I wanted to return just the firstnames of the people in the collection, I could re-write my query like so:
如果我不返回一個Person對象,只想返回collectioin中所有人的名字的集合,可以按照如下方式重寫該查詢語句:
Note above how I am no longer saying "select p", but am instead saying "select p.FirstName".? This indicates that I don't want to return back a sequence of Person objects - but rather I want to return a sequence of strings - populated from each Person object's FirstName property (which is a string).? The datatype result of this query syntax expression is consequently of type IEnumerable<string>.?
注意上邊我沒再用“select p",而是用"select p.FirstName"。這表明我不想讓查詢返回Person對象,而是想返回一個字符串--這個字符串是Person這個對象的FirstName屬性(是個字符串)中取得的。因此,該查詢表達式返回值的數據類型是IEnumerable<string>。
Sample Query Syntax Against a Database
關于對數據庫查詢的事例:
The beauty of LINQ is that I can use the exact same query syntax against any type of data.? For example, I could use the new LINQ to SQL object relational mapper (ORM) support provided in "Orcas" to model the SQL "Northwind" database with classes like below (please watch my video here to learn how to-do this):
LINQ的美在于我可以對任何類型的數據使用完全一致的查詢語法。比如,我可以用在"Orcas"中提供的新的LINQ to SQL? ORM來構建SQL 的"Northwind"數據庫,如下圖:((請看我的視頻來學習如何做:watch my video here ):
Once I've defined the class model above (and its mapping to/from the database), I can then write a query syntax expression?to fetch all products whose unitprice is greater than $99:
一旦我定義了如上的類模型(和它的 從/向 數據庫中繪制出來的圖),我可以寫一個查詢語句,查找出unitprice比99$多的產品來:
In the above code snippet I am indicating that I want to perform a LINQ query against the "Products" table on the NorthwindDataContext class?created by the ORM designer in Visual Studio "Orcas".? The "select p" indicates that I want to return a sequence of Product objects that match my query.? The datatype result of this query syntax expression is consequently of type IEnumerable<Product>.
在上邊的代碼片斷中,我指明了我想對用ORM設計器生成的NorthwindDataContext類的"Products"表進行查詢。"select p"表達了我想返回跟我的查詢想匹配的Product對象。因此,該查詢表達式的返回值類型為IEnumerable<Product>.
Just like with the previous List<Person> collection query syntax example, the C# compiler will translate our declarative query syntax into explicit extension method invocations (using Lambda expressions as the arguments).? In the case of the above LINQ to SQL example, these Lambda expressions?will then be converted into SQL commands and evaluated within SQL server (so that only those Product rows?that match the query are returned to our application).? Details on the mechanism that enables this Lambda->SQL conversion can be found in my Lambda Expressions blog post under the "Lambda Expression Trees" section.
就像剛才的查詢事例List<Person>集合那樣,C#編譯器將會把我們的聲明語句翻譯成顯示的Extension method的調用(將Lambda表達式作為參數)。在上邊的LINQ to SQL事例中,這些Lambda表達式將會被轉換成SQL命令,并且在SQL Server中進行查詢優化(如此,向我們的應用程序中只返回那些匹配了我們查詢條件的Product記錄)。關于此Lambda轉換為SQL的機制的詳細資料,在Lambda Expressions blog post 的"Lambda Expression Trees"小節下可以找到.
Query Syntax - Understanding the Where and OrderBy Clauses:
查詢語法--了解Where和OrderBy語句:
Between the opening "from" clause and closing "select" clause of a query syntax expression you can use the most common LINQ query operators to filter and transform the data you are querying.? Two of the most common clauses you'll end up using are "where" and "orderby".? These handle the filtering and ordering of results.
在查詢表達式的開始的"from"語句和結束的"select"語句之間,你可以用許多的LINQ查詢操作符來過濾和轉換你查詢的數據。兩個最常用的語句是你可以以“where"和"orderby"結束。它們處理了查詢結果的過濾和排序。
For example, to return a list of alphabetically descending?category names from the Northwind database?- filtered to only include those categories where there are more than 5 products associated with the category - we could write the below query syntax that uses LINQ to SQL to query our database:
例如,為了返回在Northwind數據庫中一個以category名稱的字母倒序排列的列表,并查出跟本類別關聯的產品記錄多于5條的記錄集,我們可以按照如下方式來寫LINQ to SQL來查詢數據庫:
In the above expression we are adding a "where c.Products.Count > 5" clause to indicate that we only want to return category names where there are more than 5 products in the category.? This takes advantage of the LINQ to SQL ORM mapping association between products and categories in our database.? In the above expression I also added a "orderby c.CategoryName descending" clause to indicate that I want to sort the results in descending order.
在上邊的表達戒,我們增加了"where c.Products.Count > 5"表達式來表明我們只想返回該類別的產品記錄數大于5的類別列表。這利用了數據庫中的products表和categories表之間的聯系。在上邊的表達式中我還加了"orderby c.CategoryName descending"語句來表達我想將產品結果倒序排列。
LINQ to SQL?will then generate the below SQL when querying the database using this expression:
然后,LINQ to 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
Notice how LINQ to SQL is smart and only returns back the single column we need (the categoryname).? It also does all of the filtering and ordering in the database layer - which makes it very efficient.
注意,LINQ to SQL是如何的精煉,并且只返回了我們想要的那一列(categoryname)。它也在數據庫這一層就做了過濾和排序,這將它變得十分高效。
Query Syntax - Transforming Data with Projections
查詢語法:用預測來轉換數據
One of the points I made earlier was that the "select" clause?indicates what data you want returned, and what shape it should be in.
剛才我提到了一點,"select"語句表明了你想返回什么數據,返回的數據是什么形式的。
For example, if you have a "select p" clause like below - where p is of type Person - then it will return a sequence of Person objects:
例如,如果有一條如下的"select p"語句-該語句中的p代表的是Person類型--那么它就是返回一個Person對象的序列:
One of the really powerful capabilities provided by LINQ and query syntax is the ability for you to define new classes that are separate from the data being queried, and to then use them to control the shape and structure?of the data being returned by the query.?
LINQ及其查詢語法提供的一個真正強大的功能是你可以定義跟查詢數據相互分離的新類,然后用定義的新類來控制查詢返回的數據。
For example, assume that we define a new "AlternatePerson" class that has a single "FullName" property instead of the separate "FirstName" and "LastName" properties that our origional "Person" class had:
例如,假如我們定義一個新類"AlternatePerson",和原有類不同的時,它沒有"FirstName"和"LastName",只有一個FunName屬性:
I could then use the below LINQ query syntax to query my origional List<Person> collection, and transform the results to be a sequence of AlternatePerson objects using the query syntax below:
我可以用如下的LINQ查詢語法來查詢出原始的List<Person>集合,并將結果集轉換為AlternatePerson對象:
Notice how we can use the new Object Initializer syntax I talked about in the first post in my language series to create a new AlternatePerson instance and set its properties within the "select" clause of our expression above.? Note also how I am assigning the "FullName" property by concatenating the FirstName and LastName properties of our origional Person class.
注意我們是如何用我在該系列中首篇帖子中提到的用新的Object Initializer語法? 來生成一個新類AlternatePerson的實例,并將它的屬性在上邊的“select"語句中聲明。同樣也要注意我如何將用拼接原有的Person類的"FirstName"和"LastName"屬性的方法將"FullName"屬性指定給AlternatePerson。
Using Query Syntax Projections with a Database
和數據庫一起使用查詢語法投影
This projection feature ends up being incredibly useful when working with data pulled from a remote data provider like a database, since it provides us with an elegant way to indicate which columns of data our ORM should actually fetch from a database.
這個投影功能在從遠程獲取數據時非常有用,比如從數據庫中獲取數據時,因為它提供給了我們一個簡潔的方法來聲明哪些字段的數據我們的ORM應該從數據庫中取出。
For example, assume I use the LINQ to SQL ORM provider to model the "Northwind" database with classes like below:
例如,假如我用LINQ to SQL ORM生成"Northwind"數據庫,如下所示:
By writing the LINQ query below, I am telling LINQ to SQL that I want a sequence of "Product" objects returned:
通過寫如下的LINQ 查詢語句,我告訴LINQ to SQL我想返回一個"Product"對象序列:
All of the columns necessary to populate?the Product class would be returned from the database as part of the above query, and the raw SQL executed by the LINQ to SQL ORM would look like below:
所有的在Product類中的列將會作為以上查詢的一部分從數據庫返回,并且LINQ to SQL ORM執行的原生的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
If I didn't need/want all of these columns?for some scenarios, I?could alternatively define a new "MyProduct" class like below that has a subset of the properties that the Product class has, as well as one additional property - "TotalRevenue" -- that the Product class doesn't have (note: for people not familiar with C#, the Decimal? syntax indicates that UnitPrice property?is a nullable value):
在某些情況下,如果我不需要,也不想返回所有的列,我可以按照如下方式來定義一個新的"MyProduct"類,該類含有Product類含有的的輔助屬性,并且也有一個額外的屬性”TotalRevenue"--該屬性是Product類中的(不熟悉C#語法者:Decimal?表達式表明了UnitPrice屬性不可為空值):
?
I can then use the projection capability of query syntax to shape the data I want returned from the database?using a query like below:
我可以用如下的查詢語句來用查詢語法的投影功能來將從數據庫中返回的數據“格式”一下:
This is indicating that instead of returning a sequence of "Product" objects,?I instead want "MyProduct" objects, and?that I only need 3?properties of them filled.? LINQ to SQL is then smart enough to?adjust the raw?SQL to execute to only return those three needed product columns from the database:
這表明了我不想讓它返回"Product"對象的序列,取而代之的是我想讓它返回“MyProduct"序列,并且我只想讓它有3列。LINQ to SQL將會非常智能地調整原來的SQL語句,以使得從數據庫中只查詢出產品的那3列:
SELECT [t0].[ProductID], [t0].[ProductName], [t0].[UnitPrice]
FROM [dbo].[Products] AS [t0]
WHERE [t0].[UnitPrice] > 99
Just to show-off, I could also populate the 4th property of the MyProduct class - which is the "TotalRevenue" property.? I want this value to be the aggregate amount of revenue that our products have sold for.??This value?isn't stored anywhere as a pre-computed column within the Northwind database.? Instead you need to perform a join between the "Products" table and the "Order Details" table and sum up all of the Order Detail rows associated with a given product.
僅僅是為了演示一下,我也可以為MyProduct類添加第4個屬性--"TotalRevenue",我想用這個屬性來合計產品已經賣出的利潤。這個不像一個已經定義好的數據列那樣存在數據庫的中。你需要在"Product"表和"Order Details"表中做一個連接,并將所有和已知產品相關聯的Order Details 記錄行求個總和。
What is cool is that I can use the LINQ "Sum" extension method on the Product class's?OrderDetails association?and?write?a?multiplication Lambda expression as part of my query syntax projection to compute this value:
酷的是,我可以用LINQ的"Sum" extension method來對Product類的OrderDetails關系做加法去處并且寫一個"Lambda"表達式做為我的查詢語法投影來計算該值:
LINQ to SQL is then smart enough to use the below SQL to perform the calculation in the SQL database:
LINQ to 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
Query Syntax - Understanding Deferred Execution, and using ToList() and ToArray()
查詢語法--了解Deferred Execution,用ToList()和ToArray()方法
By default the result of a query syntax expression is a variable of type IEnumerable<T>.? In my samples above you'll notice that all of the query syntax assignments are to IEnumerable<Product>, IEnumerable<string>, IEnumerable<Person>, IEnumerable<AlternatePerson>, and IEnumerable<MyProduct> variables.?
默認的,查詢表達式的結果是一個類型為IEnumerable<T>的變體類型,在我以上的例子中你注意到所有的表達式聲明語句是IEnumerable<Product>, IEnumerable<string>, IEnumerable<Person>, IEnumerable<AlternatePerson>, and IEnumerable<MyProduct> variables.?
One of the nice characteristics of IEnumerable<T> interfaces is that objects that implement them can defer the actual execution of the queries until a developer first attempts to iterate over the values (this is accomplished using the "yield" construct that was first introduced with C# 2.0 in VS 2005).? LINQ and query syntax expressions take advantage of this feature, and defer the actual execution of queries until the first time you loop over the results.? If you never iterate over the IEnumerable<T> result, then the query is never executed.
IEnumeralb<T>接口的其中一個特點是實現它們的對象可以延遲查詢的執行,直到開發者首次使用該聲明對象(這是在VS2005中用C#2.0介紹的"yield"結構)。LINQ 和查詢語法表達式利用了該特性,并且延遲了查詢,直到你首次遍歷結果集。如果你一直不用IEnumerale<T>結果集,它就一直不會執行。
For example, consider the below LINQ to SQL example:
例如,看如下的LINQ to SQL事例:
The database will be hit and the values to populate our Category objects will be retrieved not when the query syntax expression is declared - but rather when we first try and loop over the results (indicated above with the red arrow).
不是在查詢語法聲明時將數據庫查詢和將值加載到我們的Category對象中,而是當我們首次試圖循環結果集時(上邊用紅色箭頭表明的部分)
This deferred execution behavior ends up being really useful because?it enables some powerful composition scenarios where we can "chain" multiple LINQ queries and expressions together.? For example, we could feed the result of one expression into another - and by deferring the execution allow an ORM like LINQ to SQL to optimize the raw SQL based on the entire expression tree.? I'll show examples of how to use this in a later blog post.
這種延遲執行的行為的非常有用,因為它使得一些在我們能“鏈接”LINQ 查詢和表達式到一起的強大的組合情景成為可能。例如,我們可以將一個表達式的填充到另一個中--并且通過延遲執行,允許像LINQ to SQL的ORM根據整個表達樹來優化原始的SQL語句。在下幾篇博客中,我將展示一些如何使用延遲執行的例子。
How to evaluate the query syntax expression immediately
如何快速評估查詢表達式
If you don't want to defer the execution of queries, and instead want to execute them immediately, you can use the built-in ToList() and ToArray() operators to return either a List<T> or an array containing the results.?
如果你不想延遲執行查詢,想立即執行它們,你可以用內置的ToList()和ToArray()方法來返回一個包含結果集的或者List<T>或者是array的類型。
For example, to return a generic-based List<T> collection:
例如,返回一個基于List<T>的集合:
and to return an array:
返回一個數組:
In both cases above the database will be hit and the Category objects populated immediately.?
在上邊這兩個例子中,將會立即查詢數據庫,并且將查詢結果填充到Category對象中。
Summary
總結
Query syntax provides a very convenient declarative shorthand for expressing queries using the standard LINQ query operators.? It offers a syntax that is very readable, and which works against any type of data (any in-memory collection, array, XML content, or against remote data providers like databases, web-services, etc).? Once you become familiar with the syntax, you can immediately apply the knowledge everywhere.
查詢語法是用標準的LINQ查詢操作符來聲來為表達式聲明的一個方便的速記方法。它提供了一種增強了程序的可讀性和明了性的語法,并且易讀易寫,寫的過程中不容易出現錯誤。VS為查詢語法提供了完全的智能提示和編譯時檢查。
In the not too distant future I'll finish the last segment of this language series - which will cover the new "anonymous types" feature.? I'll then move on to cover some super practical examples of using all of these language features in the real world (especially using LINQ against databases and XML files).?
很快我將結束該語言的最后一個部分--該部分涵蓋了新的“anonymous types"特性。屆時我將用這些語言在現實世界中做一些高級實用的例子(尤其是用LINQ來對數據庫和XML文件來操作)
Hope this helps,
Scott
轉載于:https://www.cnblogs.com/hanxianlong/archive/2007/11/13/958336.html
總結
以上是生活随笔為你收集整理的再试译ScottGu's Posts 之 VS2008之语言特性--查询语法--New Orcas Language Feature: Query Syntax...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MangosCfg文件中文说明
- 下一篇: java 10套完整项目开发案例 (详细