LINQ 查詢簡介 (C#)
「查詢」(Query) 是一種從資料來源擷取資料的運算式, 而且使用專用的查詢語言來表示。 一段時間之後,針對不同類型的資料來源已開發出不同的語言,例如 SQL 是用於關聯式資料庫,而 XQuery 則是 XML。 因此,開發人員必須針對他們所需支援的資料來源類型或資料格式學習新的查詢語言。 LINQ 提供一致的模型來使用各種資料來源和格式的資料,從而簡化此情況。 在 LINQ 查詢中,您所處理的一定是物件。 不論您要查詢及轉換的資料是存在 XML 文件、SQL 資料庫、ADO.NET 資料集,還是 .NET 集合,以及其他任何有可用 LINQ 提供者 (Provider) 的格式中,都是使用相同的基本程式碼撰寫模式。
查詢作業的三個部分
所有的 LINQ 查詢作業都包含三個不同的動作:
取得資料來源。
建立查詢。
執行查詢。
下列範例示範查詢作業的三個部分在原始程式碼中的表示方式。 為了方便起見,這個範例使用整數陣列做為資料來源;不過,相同的概念也適用於其他資料來源。 本主題其他部分都會參照到這個範例。
class IntroToLINQ
{
static void Main()
{
// The Three Parts of a LINQ Query:
// 1. Data source.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
// 2. Query creation.
// numQuery is an IEnumerable<int>
var numQuery =
from num in numbers
where (num % 2) == 0
select num;
// 3. Query execution.
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
}
}
下圖顯示完整的查詢作業。 在 LINQ 中,查詢的執行與查詢本身不同;也就是說,只建立查詢變數並不能擷取任何資料。
資料來源
在前述範例中,因為資料來源是陣列,所以它已隱含泛型 IEnumerable<T> 介面的支援。 這表示它可以使用 LINQ 進行查詢。 查詢是在 foreach 陳述式中執行,而 foreach 則需要 IEnumerable 或 IEnumerable<T>。支援 IEnumerable<T> 或像是泛型 IQueryable<T> 之衍生介面的型別,都稱為「可查詢型別」(Queryable Type)。
可查詢型別不需要進行修改或特殊處理,就可以當成 LINQ 資料來源。 如果來源資料還不是記憶體中的可查詢型別,LINQ 提供者必須將它表示為可查詢型別。 例如,LINQ to XML 會將 XML 文件載入可查詢的 XElement 型別中:
// Create a data source from an XML document.
// using System.Xml.Linq;
XElement contacts = XElement.Load(@"c:\myContactList.xml");
使用 LINQ to SQL 時,請先在設計階段利用手動方式或物件關聯式設計工具 (O/R 設計工具),建立物件關聯對應。 您可以針對物件撰寫查詢,而 LINQ to SQL 則會在執行階段處理與資料庫之間的通訊。 在下列範例中,Customers 代表資料庫中的特定資料表,而查詢結果的型別 IQueryable<T> 則衍生自 IEnumerable<T>。
Northwnd db = new Northwnd(@"c:\northwnd.mdf");
// Query for customers in London.
IQueryable<Customer> custQuery =
from cust in db.Customers
where cust.City == "London"
select cust;
如需如何建立特定資料來源類型的詳細資訊,請參閱各種 LINQ 提供者的文件。 不過,基本規則十分簡單:LINQ 資料來源是支援泛型 IEnumerable<T> 介面的物件,或是繼承自此泛型介面的介面。
注意事項 |
---|
諸如 ArrayList 等支援非泛型 IEnumerable 介面的型別,也可以當成 LINQ 資料來源使用。 如需詳細資訊,請參閱HOW TO:使用 LINQ 查詢 ArrayList。 |
查詢
查詢可指定要從一個或多個資料來源擷取的資訊, 也可選擇指定該資訊在傳回之前所應採用的排序、群組方式和外形。 查詢是儲存在查詢變數中,並以查詢運算式初始化。 為了簡化撰寫查詢的程序,C# 已引入新的查詢語法。
前述範例中的查詢會傳回整數陣列中的所有偶數。 查詢運算式包含三個子句:from、where 和 select (如果您熟悉 SQL,應該已注意到這些子句的排序與 SQL 中的排序相反)。from 子句指定資料來源,where 子句套用篩選條件,而 select 子句則指定傳回項目的型別。 LINQ 查詢運算式 (C# 程式設計手冊) 章節中將會詳細討論這些查詢子句和其他查詢子句。 現在的重點是,在 LINQ 中,查詢變數本身不會進行任何動作,也不會傳回任何資料, 它只會儲存稍後執行查詢以產生結果時所需要的資訊。 如需如何在幕後建構查詢的詳細資訊,請參閱標準查詢運算子概觀。
注意事項 |
---|
查詢可以使用方法語法來表示。 如需詳細資訊,請參閱LINQ 查詢語法與方法語法的比較 (C#)。 |
查詢執行
延後執行
如前面所述,查詢變數本身只會儲存查詢命令。 實際執行查詢的作業將會延後至您反覆查看 foreach 陳述式中的查詢變數為止。 這個概念稱為「延後執行」(Deferred Execution),下列範例將加以示範:
// Query execution.
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
foreach 陳述式也是擷取查詢變數的地方。 例如,在前述查詢中,反覆運算變數 num 會保留傳回序列中的每個值 (一次一個)。
因為查詢變數本身並不會保留查詢結果,所以您可以隨意多次執行查詢變數。 例如,您的資料庫可能是由另一個應用程式持續更新。 在您的應用程式中,您可以建立一個會擷取最新資料的查詢,並按照特定的間隔執行該項查詢,以擷取不同的結果。
強制立即執行
針對某個來源項目範圍執行彙總函式的查詢必須先反覆查看這些項目。 這類查詢的範例包括 Count、Max、Average 和 First。 這些查詢執行時並未使用明確的 foreach 陳述式,因為查詢本身必須使用 foreach 才能傳回結果。 另外也請注意,這些查詢類型傳回的是單一的值,而不是 IEnumerable 集合。 下列查詢會傳回來源陣列中的偶數計數:
var evenNumQuery =
from num in numbers
where (num % 2) == 0
select num;
int evenNumCount = evenNumQuery.Count();
若要強制立即執行任何查詢並快取其結果,您可以呼叫 ToList<TSource> 或 ToArray<TSource> 方法。
List<int> numQuery2 =
(from num in numbers
where (num % 2) == 0
select num).ToList();
// or like this:
// numQuery3 is still an int[]
var numQuery3 =
(from num in numbers
where (num % 2) == 0
select num).ToArray();
您也可以將 foreach 迴圈放在緊接著查詢運算式後方的位置,以強制執行查詢。 不過,透過呼叫 ToList 或 ToArray,您可同時快取單一集合物件中的所有資料。